@standards-kit/conform 0.1.3 → 0.3.0

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.
Files changed (90) hide show
  1. package/dist/{chunk-PZ2NVKI7.js → chunk-FJZMUGYW.js} +30 -13
  2. package/dist/chunk-FJZMUGYW.js.map +1 -0
  3. package/dist/chunk-O745CMWG.js +29 -0
  4. package/dist/chunk-O745CMWG.js.map +1 -0
  5. package/dist/chunk-RHM53NLG.js +49 -0
  6. package/dist/chunk-RHM53NLG.js.map +1 -0
  7. package/dist/{chunk-RXA4FO7L.js → chunk-YKKWXHYS.js} +13 -9
  8. package/dist/chunk-YKKWXHYS.js.map +1 -0
  9. package/dist/cli/index.d.ts +3 -0
  10. package/dist/cli/process.d.ts +2 -0
  11. package/dist/cli/utils.d.ts +19 -0
  12. package/dist/cli/validate.d.ts +2 -0
  13. package/dist/cli.js +3905 -3875
  14. package/dist/cli.js.map +1 -1
  15. package/dist/{cloudwatch-KSZ4A256.js → cloudwatch-3LTDYG6G.js} +6 -10
  16. package/dist/cloudwatch-3LTDYG6G.js.map +1 -0
  17. package/dist/constants.d.ts +69 -0
  18. package/dist/core/schema.d.ts +170 -1684
  19. package/dist/{core-KB2W6SE2.js → core-LFX2BFLG.js} +3 -2
  20. package/dist/{dynamodb-5KVESCVJ.js → dynamodb-HQH3IMAI.js} +6 -10
  21. package/dist/dynamodb-HQH3IMAI.js.map +1 -0
  22. package/dist/{ec2-HKPE6GZV.js → ec2-AEPT735A.js} +6 -10
  23. package/dist/ec2-AEPT735A.js.map +1 -0
  24. package/dist/{ecs-OS3NJZTA.js → ecs-UHKCH5A7.js} +6 -10
  25. package/dist/ecs-UHKCH5A7.js.map +1 -0
  26. package/dist/{elasticache-7TCRHYYM.js → elasticache-5Y6K7GKJ.js} +6 -10
  27. package/dist/elasticache-5Y6K7GKJ.js.map +1 -0
  28. package/dist/{elb-PEDLXW5R.js → elb-CN6ELVM5.js} +6 -10
  29. package/dist/elb-CN6ELVM5.js.map +1 -0
  30. package/dist/{iam-7H5HFWVQ.js → iam-YXMHK2MV.js} +6 -2
  31. package/dist/iam-YXMHK2MV.js.map +1 -0
  32. package/dist/index.d.ts +1 -1
  33. package/dist/index.js +93 -121
  34. package/dist/index.js.map +1 -1
  35. package/dist/infra/checkers/client-factory.d.ts +45 -0
  36. package/dist/infra/schemas.d.ts +41 -533
  37. package/dist/{infra-ZQRXX7AW.js → infra-RFEWGWPW.js} +20 -18
  38. package/dist/{infra-ZQRXX7AW.js.map → infra-RFEWGWPW.js.map} +1 -1
  39. package/dist/{lambda-NFB5UILT.js → lambda-YTJOCYV5.js} +6 -10
  40. package/dist/lambda-YTJOCYV5.js.map +1 -0
  41. package/dist/mcp/standards/parser.d.ts +2 -14
  42. package/dist/{mcp-WXYRFNEV.js → mcp-T2JFU4E2.js} +4 -3
  43. package/dist/{mcp-WXYRFNEV.js.map → mcp-T2JFU4E2.js.map} +1 -1
  44. package/dist/projects/tier-loader.d.ts +10 -3
  45. package/dist/projects/types.d.ts +4 -4
  46. package/dist/{rds-KLG5O5SI.js → rds-GZ5RVPIU.js} +6 -10
  47. package/dist/rds-GZ5RVPIU.js.map +1 -0
  48. package/dist/{registry-7CDIMOLZ.js → registry-J2LVW3M2.js} +3 -2
  49. package/dist/{s3-2DH7PRVR.js → s3-53UELUWT.js} +16 -12
  50. package/dist/s3-53UELUWT.js.map +1 -0
  51. package/dist/s3-S4GXNR7H.js +53 -0
  52. package/dist/s3-S4GXNR7H.js.map +1 -0
  53. package/dist/{scan-IKEHLZXV.js → scan-BZH5IR3Z.js} +4 -3
  54. package/dist/scan-BZH5IR3Z.js.map +1 -0
  55. package/dist/{secretsmanager-MOOIHLAO.js → secretsmanager-FJKTPIXI.js} +6 -10
  56. package/dist/secretsmanager-FJKTPIXI.js.map +1 -0
  57. package/dist/{sns-Y36LVTWA.js → sns-RV64OMK2.js} +6 -10
  58. package/dist/sns-RV64OMK2.js.map +1 -0
  59. package/dist/{sqs-RRS3GRHK.js → sqs-MHBW6UFC.js} +6 -10
  60. package/dist/sqs-MHBW6UFC.js.map +1 -0
  61. package/dist/{standards-RXK5G4IG.js → standards-ALMA4VIU.js} +3 -2
  62. package/dist/{sync-XV6XBLVZ.js → sync-EGJ2CSYK.js} +3 -2
  63. package/dist/sync-EGJ2CSYK.js.map +1 -0
  64. package/dist/validate/index.d.ts +1 -1
  65. package/dist/validate/tier.d.ts +3 -0
  66. package/dist/validate/types.d.ts +3 -9
  67. package/dist/{validate-DKEJICCK.js → validate-X4K2SHYT.js} +53 -84
  68. package/dist/validate-X4K2SHYT.js.map +1 -0
  69. package/package.json +10 -16
  70. package/dist/chunk-PZ2NVKI7.js.map +0 -1
  71. package/dist/chunk-RXA4FO7L.js.map +0 -1
  72. package/dist/cloudwatch-KSZ4A256.js.map +0 -1
  73. package/dist/dynamodb-5KVESCVJ.js.map +0 -1
  74. package/dist/ec2-HKPE6GZV.js.map +0 -1
  75. package/dist/ecs-OS3NJZTA.js.map +0 -1
  76. package/dist/elasticache-7TCRHYYM.js.map +0 -1
  77. package/dist/elb-PEDLXW5R.js.map +0 -1
  78. package/dist/iam-7H5HFWVQ.js.map +0 -1
  79. package/dist/lambda-NFB5UILT.js.map +0 -1
  80. package/dist/rds-KLG5O5SI.js.map +0 -1
  81. package/dist/s3-2DH7PRVR.js.map +0 -1
  82. package/dist/scan-IKEHLZXV.js.map +0 -1
  83. package/dist/secretsmanager-MOOIHLAO.js.map +0 -1
  84. package/dist/sns-Y36LVTWA.js.map +0 -1
  85. package/dist/sqs-RRS3GRHK.js.map +0 -1
  86. package/dist/sync-XV6XBLVZ.js.map +0 -1
  87. package/dist/validate-DKEJICCK.js.map +0 -1
  88. /package/dist/{core-KB2W6SE2.js.map → core-LFX2BFLG.js.map} +0 -0
  89. /package/dist/{registry-7CDIMOLZ.js.map → registry-J2LVW3M2.js.map} +0 -0
  90. /package/dist/{standards-RXK5G4IG.js.map → standards-ALMA4VIU.js.map} +0 -0
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/mcp/standards/fetcher.ts","../src/mcp/standards/parser.ts","../src/mcp/standards/matcher.ts"],"sourcesContent":["/**\n * Fetches the standards repository from GitHub or local filesystem\n */\nimport * as fs from \"node:fs\";\nimport * as os from \"node:os\";\nimport * as path from \"node:path\";\n\nimport { execa } from \"execa\";\n\nconst DEFAULT_OWNER = \"palindrom-ai\";\nconst DEFAULT_REPO = \"standards\";\nconst CACHE_DIR = path.join(os.tmpdir(), \"cm-standards-cache\");\n\n/** Parsed GitHub source */\ninterface GitHubSource {\n type: \"github\";\n owner: string;\n repo: string;\n ref?: string;\n}\n\n/** Parsed local source */\ninterface LocalSource {\n type: \"local\";\n path: string;\n}\n\n/** Parsed source type */\ntype ParsedSource = GitHubSource | LocalSource;\n\n/** Parse github:owner/repo[@ref] format */\nfunction parseGitHubSource(source: string): GitHubSource {\n const remainder = source.slice(7); // Remove \"github:\"\n const atIndex = remainder.indexOf(\"@\");\n const ownerRepo = atIndex !== -1 ? remainder.slice(0, atIndex) : remainder;\n const ref = atIndex !== -1 ? remainder.slice(atIndex + 1) : undefined;\n const slashIndex = ownerRepo.indexOf(\"/\");\n\n if (slashIndex === -1) {\n throw new StandardsError(`Invalid GitHub source format: ${source}. Expected github:owner/repo`);\n }\n\n const owner = ownerRepo.slice(0, slashIndex);\n const repo = ownerRepo.slice(slashIndex + 1);\n\n if (!owner || !repo) {\n throw new StandardsError(`Invalid GitHub source format: ${source}. Expected github:owner/repo`);\n }\n\n return { type: \"github\", owner, repo, ref };\n}\n\n/**\n * Parse a source string into owner/repo/ref or local path.\n * Formats:\n * - \"github:owner/repo\" - GitHub repository\n * - \"github:owner/repo@ref\" - GitHub with branch/tag\n * - Local filesystem path (absolute or relative)\n */\nfunction parseSource(source: string): ParsedSource {\n if (source.startsWith(\"github:\")) {\n return parseGitHubSource(source);\n }\n return { type: \"local\", path: source };\n}\n\n/** Error class for standards fetching failures */\nexport class StandardsError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"StandardsError\";\n }\n}\n\n/** Authentication method for GitHub */\ntype AuthMethod = \"token\" | \"ssh\" | \"none\";\n\n/**\n * Detect authentication method based on environment variables.\n * Priority: CM_REGISTRY_TOKEN > GITHUB_TOKEN > SSH key detection > none\n */\nfunction detectAuthMethod(): AuthMethod {\n if (process.env.CM_REGISTRY_TOKEN || process.env.GITHUB_TOKEN) {\n return \"token\";\n }\n if (process.env.SSH_AUTH_SOCK) {\n return \"ssh\";\n }\n return \"none\";\n}\n\n/**\n * Get the authentication token from environment variables.\n */\nfunction getAuthToken(): string | undefined {\n return process.env.CM_REGISTRY_TOKEN ?? process.env.GITHUB_TOKEN;\n}\n\n/**\n * Build the git URL for a repository based on auth method.\n */\nfunction buildGitHubUrl(auth: AuthMethod, owner: string, repo: string): string {\n switch (auth) {\n case \"ssh\":\n return `git@github.com:${owner}/${repo}.git`;\n case \"token\": {\n const token = getAuthToken();\n if (token) {\n return `https://x-access-token:${token}@github.com/${owner}/${repo}.git`;\n }\n return `https://github.com/${owner}/${repo}.git`;\n }\n case \"none\":\n default:\n return `https://github.com/${owner}/${repo}.git`;\n }\n}\n\n/**\n * Update an existing cloned repository.\n */\nasync function updateExistingRepo(repoDir: string): Promise<boolean> {\n try {\n await execa(\"git\", [\"pull\", \"--ff-only\"], { cwd: repoDir, timeout: 30_000 });\n return true;\n } catch {\n // If update fails, remove the directory so it will be re-cloned\n fs.rmSync(repoDir, { recursive: true, force: true });\n return false;\n }\n}\n\n/**\n * Clone a repository from GitHub.\n */\nasync function cloneRepo(repoDir: string, owner: string, repo: string, ref?: string): Promise<void> {\n fs.mkdirSync(CACHE_DIR, { recursive: true });\n\n const auth = detectAuthMethod();\n const url = buildGitHubUrl(auth, owner, repo);\n\n try {\n const args = [\"clone\", \"--depth\", \"1\"];\n if (ref) {\n args.push(\"--branch\", ref);\n }\n args.push(url, repoDir);\n\n await execa(\"git\", args, {\n timeout: 30_000,\n });\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n if (message.includes(\"timed out\")) {\n throw new StandardsError(`Standards repo clone timed out after 30 seconds`);\n }\n throw new StandardsError(`Failed to clone standards repo: ${message}`);\n }\n}\n\n/**\n * Fetch a GitHub repository, caching it locally.\n * Returns the path to the cached repository.\n */\nasync function fetchGitHubRepo(owner: string, repo: string, ref?: string): Promise<string> {\n const cacheKey = ref ? `${owner}-${repo}-${ref}` : `${owner}-${repo}`;\n const repoDir = path.join(CACHE_DIR, cacheKey);\n\n // If repo exists, try to update it\n if (fs.existsSync(repoDir)) {\n await updateExistingRepo(repoDir);\n }\n\n // Clone if it doesn't exist (either first time or after failed update)\n if (!fs.existsSync(repoDir)) {\n await cloneRepo(repoDir, owner, repo, ref);\n }\n\n return repoDir;\n}\n\n/**\n * Resolve a local source path to an absolute path.\n */\nfunction resolveLocalPath(localPath: string, basePath?: string): string {\n if (path.isAbsolute(localPath)) {\n return localPath;\n }\n const base = basePath ?? process.cwd();\n return path.resolve(base, localPath);\n}\n\n/**\n * Fetch the standards repository from a source string.\n * Supports:\n * - \"github:owner/repo\" - GitHub repository\n * - \"github:owner/repo@ref\" - GitHub with branch/tag\n * - Local filesystem path (absolute or relative)\n *\n * @param source - Source string to fetch from\n * @param basePath - Base path for resolving relative local paths (defaults to cwd)\n * @returns Path to the standards repository\n */\nexport async function fetchStandardsRepoFromSource(\n source: string,\n basePath?: string\n): Promise<string> {\n const parsed = parseSource(source);\n\n if (parsed.type === \"local\") {\n const resolvedPath = resolveLocalPath(parsed.path, basePath);\n if (!fs.existsSync(resolvedPath)) {\n throw new StandardsError(`Local standards path does not exist: ${resolvedPath}`);\n }\n return resolvedPath;\n }\n\n return fetchGitHubRepo(parsed.owner, parsed.repo, parsed.ref);\n}\n\n/**\n * Fetch the default standards repository, caching it locally.\n * Returns the path to the cached repository.\n */\nexport async function fetchStandardsRepo(): Promise<string> {\n return fetchGitHubRepo(DEFAULT_OWNER, DEFAULT_REPO);\n}\n\n/**\n * Get the path to the guidelines directory.\n */\nexport function getGuidelinesDir(repoPath: string): string {\n return path.join(repoPath, \"guidelines\");\n}\n\n/**\n * Get the path to the rulesets directory.\n */\nexport function getRulesetsDir(repoPath: string): string {\n return path.join(repoPath, \"rulesets\");\n}\n","/**\n * Parser for guideline markdown files with YAML frontmatter\n */\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\n\nimport matter from \"gray-matter\";\nimport { z } from \"zod\";\n\nimport { type Guideline, type GuidelineListItem, type Ruleset } from \"./types.js\";\nimport { StandardsError } from \"./fetcher.js\";\n\n/** Zod schema for validating guideline frontmatter */\nexport const frontmatterSchema = z.object({\n id: z.string(),\n title: z.string(),\n category: z.string(),\n priority: z.number(),\n tags: z.array(z.string()),\n});\n\n/**\n * Parse a guideline markdown file content into a Guideline object.\n */\nexport function parseGuideline(fileContent: string, filename: string): Guideline {\n const { data, content } = matter(fileContent);\n\n const result = frontmatterSchema.safeParse(data);\n if (!result.success) {\n const errors = result.error.errors.map((e) => `${e.path.join(\".\")}: ${e.message}`).join(\", \");\n throw new StandardsError(`Invalid frontmatter in ${filename}: ${errors}`);\n }\n\n return {\n ...result.data,\n content: content.trim(),\n };\n}\n\n/**\n * Load all guidelines from a directory.\n */\nexport function loadAllGuidelines(guidelinesDir: string): Guideline[] {\n if (!fs.existsSync(guidelinesDir)) {\n throw new StandardsError(`Guidelines directory not found: ${guidelinesDir}`);\n }\n\n const files = fs.readdirSync(guidelinesDir).filter((f) => f.endsWith(\".md\"));\n const guidelines: Guideline[] = [];\n\n for (const file of files) {\n const filePath = path.join(guidelinesDir, file);\n const content = fs.readFileSync(filePath, \"utf-8\");\n\n try {\n guidelines.push(parseGuideline(content, file));\n } catch (error) {\n // Skip files that fail to parse, log warning\n console.warn(`Warning: Failed to parse guideline ${file}: ${error}`);\n }\n }\n\n return guidelines;\n}\n\n/**\n * Load a single guideline by ID.\n */\nexport function loadGuideline(guidelinesDir: string, id: string): Guideline | null {\n const filePath = path.join(guidelinesDir, `${id}.md`);\n\n if (!fs.existsSync(filePath)) {\n return null;\n }\n\n const content = fs.readFileSync(filePath, \"utf-8\");\n return parseGuideline(content, `${id}.md`);\n}\n\n/**\n * Convert guidelines to list items (summary format).\n */\nexport function toListItems(guidelines: Guideline[]): GuidelineListItem[] {\n return guidelines.map((g) => ({\n id: g.id,\n title: g.title,\n tags: g.tags,\n category: g.category,\n }));\n}\n\n/**\n * Load a ruleset file by ID.\n */\nexport function loadRuleset(rulesetsDir: string, id: string): Ruleset | null {\n const filePath = path.join(rulesetsDir, `${id}.toml`);\n\n if (!fs.existsSync(filePath)) {\n return null;\n }\n\n const content = fs.readFileSync(filePath, \"utf-8\");\n return { id, content };\n}\n\n/**\n * List all available ruleset IDs.\n */\nexport function listRulesets(rulesetsDir: string): string[] {\n if (!fs.existsSync(rulesetsDir)) {\n return [];\n }\n\n return fs\n .readdirSync(rulesetsDir)\n .filter((f) => f.endsWith(\".toml\"))\n .map((f) => f.replace(\".toml\", \"\"));\n}\n","/**\n * Smart keyword matching logic for guidelines\n */\nimport { type Guideline, type MatchedGuideline } from \"./types.js\";\n\n/**\n * Parse a context string into keywords.\n * Extracts words, lowercases them, and removes duplicates.\n */\nexport function parseContext(context: string): string[] {\n const words = context\n .toLowerCase()\n .split(/[\\s,.\\-_/]+/)\n .filter((word) => word.length > 1);\n\n return [...new Set(words)];\n}\n\n/**\n * Score a guideline based on how many keywords match its tags.\n */\nexport function scoreGuideline(guideline: Guideline, keywords: string[]): number {\n const tags = new Set(guideline.tags.map((t) => t.toLowerCase()));\n let score = 0;\n\n for (const keyword of keywords) {\n if (tags.has(keyword)) {\n score++;\n }\n }\n\n // Also check if keyword appears in category or id\n const category = guideline.category.toLowerCase();\n const id = guideline.id.toLowerCase();\n\n for (const keyword of keywords) {\n if (category.includes(keyword) || id.includes(keyword)) {\n score += 0.5; // Partial match bonus\n }\n }\n\n return score;\n}\n\n/**\n * Match guidelines against a context string.\n * Returns guidelines sorted by score (descending) then priority (ascending).\n */\nexport function matchGuidelines(\n guidelines: Guideline[],\n context: string,\n limit?: number\n): MatchedGuideline[] {\n const keywords = parseContext(context);\n\n if (keywords.length === 0) {\n return [];\n }\n\n const scored = guidelines\n .map((guideline) => ({\n guideline,\n score: scoreGuideline(guideline, keywords),\n }))\n .filter((m) => m.score > 0);\n\n // Sort by score descending, then by priority ascending\n scored.sort((a, b) => {\n if (b.score !== a.score) {\n return b.score - a.score;\n }\n return a.guideline.priority - b.guideline.priority;\n });\n\n return limit ? scored.slice(0, limit) : scored;\n}\n\n/**\n * Compose matched guidelines into a single markdown document.\n */\nexport function composeGuidelines(matches: MatchedGuideline[]): string {\n if (matches.length === 0) {\n return \"No matching guidelines found for the given context.\";\n }\n\n const sections = matches.map((m) => {\n const { guideline } = m;\n return `# ${guideline.title}\\n\\n**Category:** ${guideline.category} | **Priority:** ${guideline.priority}\\n**Tags:** ${guideline.tags.join(\", \")}\\n\\n${guideline.content}`;\n });\n\n return sections.join(\"\\n\\n---\\n\\n\");\n}\n"],"mappings":"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","names":["fs","path"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/infra/checkers/cloudwatch.ts"],"sourcesContent":["/**\n * CloudWatch Logs resource checker\n */\n\nimport { CloudWatchLogsClient, DescribeLogGroupsCommand } from \"@aws-sdk/client-cloudwatch-logs\";\n\nimport type { ParsedArn, ResourceCheckResult } from \"../types.js\";\nimport type { ResourceChecker } from \"./types.js\";\n\n/**\n * Cache of CloudWatch Logs clients by region\n */\nconst clientCache = new Map<string, CloudWatchLogsClient>();\n\n/**\n * Get or create a CloudWatch Logs client for a region\n */\nfunction getClient(region: string): CloudWatchLogsClient {\n let client = clientCache.get(region);\n if (!client) {\n client = new CloudWatchLogsClient({ region });\n clientCache.set(region, client);\n }\n return client;\n}\n\n/**\n * CloudWatch Logs log group checker\n */\nexport const CloudWatchLogsChecker: ResourceChecker = {\n async check(arn: ParsedArn): Promise<ResourceCheckResult> {\n const { resourceId, region, raw } = arn;\n\n const client = getClient(region);\n\n try {\n // DescribeLogGroups filters by prefix, so we need to check the results\n const response = await client.send(\n new DescribeLogGroupsCommand({\n logGroupNamePrefix: resourceId,\n limit: 1,\n })\n );\n\n // Check if we found an exact match\n const found = response.logGroups?.some((lg) => lg.logGroupName === resourceId);\n\n return {\n arn: raw,\n exists: Boolean(found),\n service: \"logs\",\n resourceType: \"log-group\",\n resourceId,\n };\n } catch (error) {\n const err = error as Error & { name?: string };\n\n if (err.name === \"ResourceNotFoundException\") {\n return {\n arn: raw,\n exists: false,\n service: \"logs\",\n resourceType: \"log-group\",\n resourceId,\n };\n }\n\n return {\n arn: raw,\n exists: false,\n error: err.message || \"Unknown error\",\n service: \"logs\",\n resourceType: \"log-group\",\n resourceId,\n };\n }\n },\n};\n"],"mappings":";AAIA,SAAS,sBAAsB,gCAAgC;AAQ/D,IAAM,cAAc,oBAAI,IAAkC;AAK1D,SAAS,UAAU,QAAsC;AACvD,MAAI,SAAS,YAAY,IAAI,MAAM;AACnC,MAAI,CAAC,QAAQ;AACX,aAAS,IAAI,qBAAqB,EAAE,OAAO,CAAC;AAC5C,gBAAY,IAAI,QAAQ,MAAM;AAAA,EAChC;AACA,SAAO;AACT;AAKO,IAAM,wBAAyC;AAAA,EACpD,MAAM,MAAM,KAA8C;AACxD,UAAM,EAAE,YAAY,QAAQ,IAAI,IAAI;AAEpC,UAAM,SAAS,UAAU,MAAM;AAE/B,QAAI;AAEF,YAAM,WAAW,MAAM,OAAO;AAAA,QAC5B,IAAI,yBAAyB;AAAA,UAC3B,oBAAoB;AAAA,UACpB,OAAO;AAAA,QACT,CAAC;AAAA,MACH;AAGA,YAAM,QAAQ,SAAS,WAAW,KAAK,CAAC,OAAO,GAAG,iBAAiB,UAAU;AAE7E,aAAO;AAAA,QACL,KAAK;AAAA,QACL,QAAQ,QAAQ,KAAK;AAAA,QACrB,SAAS;AAAA,QACT,cAAc;AAAA,QACd;AAAA,MACF;AAAA,IACF,SAAS,OAAO;AACd,YAAM,MAAM;AAEZ,UAAI,IAAI,SAAS,6BAA6B;AAC5C,eAAO;AAAA,UACL,KAAK;AAAA,UACL,QAAQ;AAAA,UACR,SAAS;AAAA,UACT,cAAc;AAAA,UACd;AAAA,QACF;AAAA,MACF;AAEA,aAAO;AAAA,QACL,KAAK;AAAA,QACL,QAAQ;AAAA,QACR,OAAO,IAAI,WAAW;AAAA,QACtB,SAAS;AAAA,QACT,cAAc;AAAA,QACd;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/infra/checkers/dynamodb.ts"],"sourcesContent":["/**\n * DynamoDB resource checker\n */\n\nimport { DescribeTableCommand, DynamoDBClient } from \"@aws-sdk/client-dynamodb\";\n\nimport type { ParsedArn, ResourceCheckResult } from \"../types.js\";\nimport type { ResourceChecker } from \"./types.js\";\n\n/**\n * Cache of DynamoDB clients by region\n */\nconst clientCache = new Map<string, DynamoDBClient>();\n\n/**\n * Get or create a DynamoDB client for a region\n */\nfunction getClient(region: string): DynamoDBClient {\n let client = clientCache.get(region);\n if (!client) {\n client = new DynamoDBClient({ region });\n clientCache.set(region, client);\n }\n return client;\n}\n\n/**\n * DynamoDB table checker\n */\nexport const DynamoDBChecker: ResourceChecker = {\n async check(arn: ParsedArn): Promise<ResourceCheckResult> {\n const { resourceType, resourceId, region, raw } = arn;\n\n // Extract table name (might be \"table-name\" or \"table-name/index/index-name\")\n const tableName = resourceId.split(\"/\")[0];\n\n const client = getClient(region);\n\n try {\n await client.send(new DescribeTableCommand({ TableName: tableName }));\n return {\n arn: raw,\n exists: true,\n service: \"dynamodb\",\n resourceType,\n resourceId,\n };\n } catch (error) {\n const err = error as Error & { name?: string };\n\n if (err.name === \"ResourceNotFoundException\") {\n return {\n arn: raw,\n exists: false,\n service: \"dynamodb\",\n resourceType,\n resourceId,\n };\n }\n\n return {\n arn: raw,\n exists: false,\n error: err.message || \"Unknown error\",\n service: \"dynamodb\",\n resourceType,\n resourceId,\n };\n }\n },\n};\n"],"mappings":";AAIA,SAAS,sBAAsB,sBAAsB;AAQrD,IAAM,cAAc,oBAAI,IAA4B;AAKpD,SAAS,UAAU,QAAgC;AACjD,MAAI,SAAS,YAAY,IAAI,MAAM;AACnC,MAAI,CAAC,QAAQ;AACX,aAAS,IAAI,eAAe,EAAE,OAAO,CAAC;AACtC,gBAAY,IAAI,QAAQ,MAAM;AAAA,EAChC;AACA,SAAO;AACT;AAKO,IAAM,kBAAmC;AAAA,EAC9C,MAAM,MAAM,KAA8C;AACxD,UAAM,EAAE,cAAc,YAAY,QAAQ,IAAI,IAAI;AAGlD,UAAM,YAAY,WAAW,MAAM,GAAG,EAAE,CAAC;AAEzC,UAAM,SAAS,UAAU,MAAM;AAE/B,QAAI;AACF,YAAM,OAAO,KAAK,IAAI,qBAAqB,EAAE,WAAW,UAAU,CAAC,CAAC;AACpE,aAAO;AAAA,QACL,KAAK;AAAA,QACL,QAAQ;AAAA,QACR,SAAS;AAAA,QACT;AAAA,QACA;AAAA,MACF;AAAA,IACF,SAAS,OAAO;AACd,YAAM,MAAM;AAEZ,UAAI,IAAI,SAAS,6BAA6B;AAC5C,eAAO;AAAA,UACL,KAAK;AAAA,UACL,QAAQ;AAAA,UACR,SAAS;AAAA,UACT;AAAA,UACA;AAAA,QACF;AAAA,MACF;AAEA,aAAO;AAAA,QACL,KAAK;AAAA,QACL,QAAQ;AAAA,QACR,OAAO,IAAI,WAAW;AAAA,QACtB,SAAS;AAAA,QACT;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/infra/checkers/ec2.ts"],"sourcesContent":["/**\n * EC2 resource checker\n *\n * Supports:\n * - Instances\n * - Security groups\n * - Key pairs\n */\n\nimport {\n DescribeInstancesCommand,\n DescribeSecurityGroupsCommand,\n DescribeKeyPairsCommand,\n EC2Client,\n} from \"@aws-sdk/client-ec2\";\n\nimport type { ParsedArn, ResourceCheckResult } from \"../types.js\";\nimport type { ResourceChecker } from \"./types.js\";\n\n/**\n * Cache of EC2 clients by region\n */\nconst clientCache = new Map<string, EC2Client>();\n\n/**\n * Get or create an EC2 client for a region\n */\nfunction getClient(region: string): EC2Client {\n let client = clientCache.get(region);\n if (!client) {\n client = new EC2Client({ region });\n clientCache.set(region, client);\n }\n return client;\n}\n\n/**\n * Check if an EC2 instance exists\n */\nasync function checkInstance(\n client: EC2Client,\n arn: ParsedArn\n): Promise<ResourceCheckResult> {\n const { resourceId, raw } = arn;\n\n try {\n const response = await client.send(\n new DescribeInstancesCommand({ InstanceIds: [resourceId] })\n );\n\n const instance = response.Reservations?.[0]?.Instances?.[0];\n const exists = !!instance && instance.State?.Name !== \"terminated\";\n\n return {\n arn: raw,\n exists,\n service: \"ec2\",\n resourceType: \"instance\",\n resourceId,\n };\n } catch (error) {\n const err = error as Error & { name?: string };\n\n if (err.name === \"InvalidInstanceID.NotFound\") {\n return {\n arn: raw,\n exists: false,\n service: \"ec2\",\n resourceType: \"instance\",\n resourceId,\n };\n }\n\n return {\n arn: raw,\n exists: false,\n error: err.message || \"Unknown error\",\n service: \"ec2\",\n resourceType: \"instance\",\n resourceId,\n };\n }\n}\n\n/**\n * Check if an EC2 security group exists\n */\nasync function checkSecurityGroup(\n client: EC2Client,\n arn: ParsedArn\n): Promise<ResourceCheckResult> {\n const { resourceId, raw } = arn;\n\n try {\n const response = await client.send(\n new DescribeSecurityGroupsCommand({ GroupIds: [resourceId] })\n );\n\n const securityGroup = response.SecurityGroups?.[0];\n const exists = !!securityGroup;\n\n return {\n arn: raw,\n exists,\n service: \"ec2\",\n resourceType: \"security-group\",\n resourceId,\n };\n } catch (error) {\n const err = error as Error & { name?: string };\n\n if (err.name === \"InvalidGroup.NotFound\") {\n return {\n arn: raw,\n exists: false,\n service: \"ec2\",\n resourceType: \"security-group\",\n resourceId,\n };\n }\n\n return {\n arn: raw,\n exists: false,\n error: err.message || \"Unknown error\",\n service: \"ec2\",\n resourceType: \"security-group\",\n resourceId,\n };\n }\n}\n\n/**\n * Check if an EC2 key pair exists\n */\nasync function checkKeyPair(\n client: EC2Client,\n arn: ParsedArn\n): Promise<ResourceCheckResult> {\n const { resourceId, raw } = arn;\n\n try {\n const response = await client.send(\n new DescribeKeyPairsCommand({ KeyNames: [resourceId] })\n );\n\n const keyPair = response.KeyPairs?.[0];\n const exists = !!keyPair;\n\n return {\n arn: raw,\n exists,\n service: \"ec2\",\n resourceType: \"key-pair\",\n resourceId,\n };\n } catch (error) {\n const err = error as Error & { name?: string };\n\n if (err.name === \"InvalidKeyPair.NotFound\") {\n return {\n arn: raw,\n exists: false,\n service: \"ec2\",\n resourceType: \"key-pair\",\n resourceId,\n };\n }\n\n return {\n arn: raw,\n exists: false,\n error: err.message || \"Unknown error\",\n service: \"ec2\",\n resourceType: \"key-pair\",\n resourceId,\n };\n }\n}\n\n/**\n * EC2 resource checker\n */\nexport const EC2Checker: ResourceChecker = {\n async check(arn: ParsedArn): Promise<ResourceCheckResult> {\n const { resourceType, resourceId, region, raw } = arn;\n const client = getClient(region);\n\n switch (resourceType) {\n case \"instance\":\n return checkInstance(client, arn);\n\n case \"security-group\":\n return checkSecurityGroup(client, arn);\n\n case \"key-pair\":\n return checkKeyPair(client, arn);\n\n default:\n return {\n arn: raw,\n exists: false,\n error: `Unsupported EC2 resource type: ${resourceType}`,\n service: \"ec2\",\n resourceType,\n resourceId,\n };\n }\n },\n};\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/infra/checkers/ecs.ts"],"sourcesContent":["/**\n * ECS resource checker\n *\n * Supports:\n * - Clusters\n * - Services\n * - Task definitions\n */\n\nimport {\n DescribeClustersCommand,\n DescribeServicesCommand,\n DescribeTaskDefinitionCommand,\n ECSClient,\n} from \"@aws-sdk/client-ecs\";\n\nimport type { ParsedArn, ResourceCheckResult } from \"../types.js\";\nimport type { ResourceChecker } from \"./types.js\";\n\n/**\n * Cache of ECS clients by region\n */\nconst clientCache = new Map<string, ECSClient>();\n\n/**\n * Get or create an ECS client for a region\n */\nfunction getClient(region: string): ECSClient {\n let client = clientCache.get(region);\n if (!client) {\n client = new ECSClient({ region });\n clientCache.set(region, client);\n }\n return client;\n}\n\n/**\n * Check if an ECS cluster exists\n */\nasync function checkCluster(\n client: ECSClient,\n arn: ParsedArn\n): Promise<ResourceCheckResult> {\n const { resourceId, raw } = arn;\n\n try {\n const response = await client.send(\n new DescribeClustersCommand({ clusters: [raw] })\n );\n\n const cluster = response.clusters?.[0];\n const exists = cluster?.status === \"ACTIVE\";\n\n return {\n arn: raw,\n exists,\n service: \"ecs\",\n resourceType: \"cluster\",\n resourceId,\n };\n } catch (error) {\n const err = error as Error;\n return {\n arn: raw,\n exists: false,\n error: err.message || \"Unknown error\",\n service: \"ecs\",\n resourceType: \"cluster\",\n resourceId,\n };\n }\n}\n\n/**\n * Check if an ECS service exists\n *\n * Service ARN format: arn:aws:ecs:region:account:service/cluster/service-name\n */\nasync function checkService(\n client: ECSClient,\n arn: ParsedArn\n): Promise<ResourceCheckResult> {\n const { resourceId, raw, accountId, region } = arn;\n\n // resourceId format: cluster-name/service-name\n const parts = resourceId.split(\"/\");\n if (parts.length < 2) {\n return {\n arn: raw,\n exists: false,\n error: \"Invalid service ARN format\",\n service: \"ecs\",\n resourceType: \"service\",\n resourceId,\n };\n }\n\n const clusterName = parts[0];\n const serviceName = parts[1];\n const clusterArn = `arn:aws:ecs:${region}:${accountId}:cluster/${clusterName}`;\n\n try {\n const response = await client.send(\n new DescribeServicesCommand({\n cluster: clusterArn,\n services: [serviceName],\n })\n );\n\n const service = response.services?.[0];\n const exists = service?.status === \"ACTIVE\";\n\n return {\n arn: raw,\n exists,\n service: \"ecs\",\n resourceType: \"service\",\n resourceId,\n };\n } catch (error) {\n const err = error as Error;\n return {\n arn: raw,\n exists: false,\n error: err.message || \"Unknown error\",\n service: \"ecs\",\n resourceType: \"service\",\n resourceId,\n };\n }\n}\n\n/**\n * Check if an ECS task definition exists\n *\n * Task definition ARN format: arn:aws:ecs:region:account:task-definition/name:revision\n * or: arn:aws:ecs:region:account:task-definition/name (latest)\n */\nasync function checkTaskDefinition(\n client: ECSClient,\n arn: ParsedArn\n): Promise<ResourceCheckResult> {\n const { resourceId, raw } = arn;\n\n try {\n const response = await client.send(\n new DescribeTaskDefinitionCommand({ taskDefinition: raw })\n );\n\n const taskDef = response.taskDefinition;\n const exists = taskDef?.status === \"ACTIVE\";\n\n return {\n arn: raw,\n exists,\n service: \"ecs\",\n resourceType: \"task-definition\",\n resourceId,\n };\n } catch (error) {\n const err = error as Error;\n return {\n arn: raw,\n exists: false,\n error: err.message || \"Unknown error\",\n service: \"ecs\",\n resourceType: \"task-definition\",\n resourceId,\n };\n }\n}\n\n/**\n * ECS resource checker\n */\nexport const ECSChecker: ResourceChecker = {\n async check(arn: ParsedArn): Promise<ResourceCheckResult> {\n const { resourceType, resourceId, region, raw } = arn;\n const client = getClient(region);\n\n switch (resourceType) {\n case \"cluster\":\n return checkCluster(client, arn);\n\n case \"service\":\n return checkService(client, arn);\n\n case \"task-definition\":\n return checkTaskDefinition(client, arn);\n\n default:\n return {\n arn: raw,\n exists: false,\n error: `Unsupported ECS resource type: ${resourceType}`,\n service: \"ecs\",\n resourceType,\n resourceId,\n };\n }\n },\n};\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/infra/checkers/elasticache.ts"],"sourcesContent":["/**\n * ElastiCache resource checker\n *\n * Supports:\n * - Cache clusters\n * - Subnet groups\n * - Replication groups\n */\n\nimport {\n DescribeCacheClustersCommand,\n DescribeCacheSubnetGroupsCommand,\n DescribeReplicationGroupsCommand,\n ElastiCacheClient,\n} from \"@aws-sdk/client-elasticache\";\n\nimport type { ParsedArn, ResourceCheckResult } from \"../types.js\";\nimport type { ResourceChecker } from \"./types.js\";\n\n/**\n * Cache of ElastiCache clients by region\n */\nconst clientCache = new Map<string, ElastiCacheClient>();\n\n/**\n * Get or create an ElastiCache client for a region\n */\nfunction getClient(region: string): ElastiCacheClient {\n let client = clientCache.get(region);\n if (!client) {\n client = new ElastiCacheClient({ region });\n clientCache.set(region, client);\n }\n return client;\n}\n\n/**\n * Check if an ElastiCache cluster exists\n */\nasync function checkCacheCluster(\n client: ElastiCacheClient,\n arn: ParsedArn\n): Promise<ResourceCheckResult> {\n const { resourceId, raw } = arn;\n\n try {\n const response = await client.send(\n new DescribeCacheClustersCommand({ CacheClusterId: resourceId })\n );\n\n const cluster = response.CacheClusters?.[0];\n const exists = !!cluster && cluster.CacheClusterStatus !== \"deleting\";\n\n return {\n arn: raw,\n exists,\n service: \"elasticache\",\n resourceType: \"cluster\",\n resourceId,\n };\n } catch (error) {\n const err = error as Error & { name?: string };\n\n if (err.name === \"CacheClusterNotFoundFault\") {\n return {\n arn: raw,\n exists: false,\n service: \"elasticache\",\n resourceType: \"cluster\",\n resourceId,\n };\n }\n\n return {\n arn: raw,\n exists: false,\n error: err.message || \"Unknown error\",\n service: \"elasticache\",\n resourceType: \"cluster\",\n resourceId,\n };\n }\n}\n\n/**\n * Check if an ElastiCache subnet group exists\n */\nasync function checkSubnetGroup(\n client: ElastiCacheClient,\n arn: ParsedArn\n): Promise<ResourceCheckResult> {\n const { resourceId, raw } = arn;\n\n try {\n const response = await client.send(\n new DescribeCacheSubnetGroupsCommand({ CacheSubnetGroupName: resourceId })\n );\n\n const subnetGroup = response.CacheSubnetGroups?.[0];\n const exists = !!subnetGroup;\n\n return {\n arn: raw,\n exists,\n service: \"elasticache\",\n resourceType: \"subnetgroup\",\n resourceId,\n };\n } catch (error) {\n const err = error as Error & { name?: string };\n\n if (err.name === \"CacheSubnetGroupNotFoundFault\") {\n return {\n arn: raw,\n exists: false,\n service: \"elasticache\",\n resourceType: \"subnetgroup\",\n resourceId,\n };\n }\n\n return {\n arn: raw,\n exists: false,\n error: err.message || \"Unknown error\",\n service: \"elasticache\",\n resourceType: \"subnetgroup\",\n resourceId,\n };\n }\n}\n\n/**\n * Check if an ElastiCache replication group exists\n */\nasync function checkReplicationGroup(\n client: ElastiCacheClient,\n arn: ParsedArn\n): Promise<ResourceCheckResult> {\n const { resourceId, raw } = arn;\n\n try {\n const response = await client.send(\n new DescribeReplicationGroupsCommand({ ReplicationGroupId: resourceId })\n );\n\n const replicationGroup = response.ReplicationGroups?.[0];\n const exists = !!replicationGroup && replicationGroup.Status !== \"deleting\";\n\n return {\n arn: raw,\n exists,\n service: \"elasticache\",\n resourceType: \"replicationgroup\",\n resourceId,\n };\n } catch (error) {\n const err = error as Error & { name?: string };\n\n if (err.name === \"ReplicationGroupNotFoundFault\") {\n return {\n arn: raw,\n exists: false,\n service: \"elasticache\",\n resourceType: \"replicationgroup\",\n resourceId,\n };\n }\n\n return {\n arn: raw,\n exists: false,\n error: err.message || \"Unknown error\",\n service: \"elasticache\",\n resourceType: \"replicationgroup\",\n resourceId,\n };\n }\n}\n\n/**\n * ElastiCache resource checker\n */\nexport const ElastiCacheChecker: ResourceChecker = {\n async check(arn: ParsedArn): Promise<ResourceCheckResult> {\n const { resourceType, resourceId, region, raw } = arn;\n const client = getClient(region);\n\n switch (resourceType) {\n case \"cluster\":\n return checkCacheCluster(client, arn);\n\n case \"subnetgroup\":\n return checkSubnetGroup(client, arn);\n\n case \"replicationgroup\":\n return checkReplicationGroup(client, arn);\n\n default:\n return {\n arn: raw,\n exists: false,\n error: `Unsupported ElastiCache resource type: ${resourceType}`,\n service: \"elasticache\",\n resourceType,\n resourceId,\n };\n }\n },\n};\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/infra/checkers/elb.ts"],"sourcesContent":["/**\n * Elastic Load Balancing v2 resource checker\n *\n * Supports:\n * - Load balancers (ALB, NLB, GLB)\n * - Target groups\n * - Listeners\n */\n\nimport {\n DescribeLoadBalancersCommand,\n DescribeTargetGroupsCommand,\n DescribeListenersCommand,\n ElasticLoadBalancingV2Client,\n} from \"@aws-sdk/client-elastic-load-balancing-v2\";\n\nimport type { ParsedArn, ResourceCheckResult } from \"../types.js\";\nimport type { ResourceChecker } from \"./types.js\";\n\n/**\n * Cache of ELBv2 clients by region\n */\nconst clientCache = new Map<string, ElasticLoadBalancingV2Client>();\n\n/**\n * Get or create an ELBv2 client for a region\n */\nfunction getClient(region: string): ElasticLoadBalancingV2Client {\n let client = clientCache.get(region);\n if (!client) {\n client = new ElasticLoadBalancingV2Client({ region });\n clientCache.set(region, client);\n }\n return client;\n}\n\n/**\n * Check if a load balancer exists\n */\nasync function checkLoadBalancer(\n client: ElasticLoadBalancingV2Client,\n arn: ParsedArn\n): Promise<ResourceCheckResult> {\n const { resourceId, raw } = arn;\n\n try {\n const response = await client.send(\n new DescribeLoadBalancersCommand({ LoadBalancerArns: [raw] })\n );\n\n const loadBalancer = response.LoadBalancers?.[0];\n const exists =\n !!loadBalancer &&\n loadBalancer.State?.Code !== \"failed\" &&\n loadBalancer.State?.Code !== \"active_impaired\";\n\n return {\n arn: raw,\n exists,\n service: \"elasticloadbalancing\",\n resourceType: \"loadbalancer\",\n resourceId,\n };\n } catch (error) {\n const err = error as Error & { name?: string };\n\n if (err.name === \"LoadBalancerNotFoundException\") {\n return {\n arn: raw,\n exists: false,\n service: \"elasticloadbalancing\",\n resourceType: \"loadbalancer\",\n resourceId,\n };\n }\n\n return {\n arn: raw,\n exists: false,\n error: err.message || \"Unknown error\",\n service: \"elasticloadbalancing\",\n resourceType: \"loadbalancer\",\n resourceId,\n };\n }\n}\n\n/**\n * Check if a target group exists\n */\nasync function checkTargetGroup(\n client: ElasticLoadBalancingV2Client,\n arn: ParsedArn\n): Promise<ResourceCheckResult> {\n const { resourceId, raw } = arn;\n\n try {\n const response = await client.send(\n new DescribeTargetGroupsCommand({ TargetGroupArns: [raw] })\n );\n\n const targetGroup = response.TargetGroups?.[0];\n const exists = !!targetGroup;\n\n return {\n arn: raw,\n exists,\n service: \"elasticloadbalancing\",\n resourceType: \"targetgroup\",\n resourceId,\n };\n } catch (error) {\n const err = error as Error & { name?: string };\n\n if (err.name === \"TargetGroupNotFoundException\") {\n return {\n arn: raw,\n exists: false,\n service: \"elasticloadbalancing\",\n resourceType: \"targetgroup\",\n resourceId,\n };\n }\n\n return {\n arn: raw,\n exists: false,\n error: err.message || \"Unknown error\",\n service: \"elasticloadbalancing\",\n resourceType: \"targetgroup\",\n resourceId,\n };\n }\n}\n\n/**\n * Check if a listener exists\n */\nasync function checkListener(\n client: ElasticLoadBalancingV2Client,\n arn: ParsedArn\n): Promise<ResourceCheckResult> {\n const { resourceId, raw } = arn;\n\n try {\n const response = await client.send(\n new DescribeListenersCommand({ ListenerArns: [raw] })\n );\n\n const listener = response.Listeners?.[0];\n const exists = !!listener;\n\n return {\n arn: raw,\n exists,\n service: \"elasticloadbalancing\",\n resourceType: \"listener\",\n resourceId,\n };\n } catch (error) {\n const err = error as Error & { name?: string };\n\n if (err.name === \"ListenerNotFoundException\") {\n return {\n arn: raw,\n exists: false,\n service: \"elasticloadbalancing\",\n resourceType: \"listener\",\n resourceId,\n };\n }\n\n return {\n arn: raw,\n exists: false,\n error: err.message || \"Unknown error\",\n service: \"elasticloadbalancing\",\n resourceType: \"listener\",\n resourceId,\n };\n }\n}\n\n/**\n * Elastic Load Balancing resource checker\n */\nexport const ELBChecker: ResourceChecker = {\n async check(arn: ParsedArn): Promise<ResourceCheckResult> {\n const { resourceType, resourceId, region, raw } = arn;\n const client = getClient(region);\n\n switch (resourceType) {\n case \"loadbalancer\":\n return checkLoadBalancer(client, arn);\n\n case \"targetgroup\":\n return checkTargetGroup(client, arn);\n\n case \"listener\":\n return checkListener(client, arn);\n\n default:\n return {\n arn: raw,\n exists: false,\n error: `Unsupported ELB resource type: ${resourceType}`,\n service: \"elasticloadbalancing\",\n resourceType,\n resourceId,\n };\n }\n },\n};\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/infra/checkers/iam.ts"],"sourcesContent":["/**\n * IAM resource checker\n */\n\nimport { GetPolicyCommand, GetRoleCommand, IAMClient } from \"@aws-sdk/client-iam\";\n\nimport type { ParsedArn, ResourceCheckResult } from \"../types.js\";\nimport type { ResourceChecker } from \"./types.js\";\n\n/**\n * IAM is global, so we only need one client\n */\nlet client: IAMClient | null = null;\n\n/**\n * Get or create the IAM client\n */\nfunction getClient(): IAMClient {\n // IAM is global, use us-east-1\n client ??= new IAMClient({ region: \"us-east-1\" });\n return client;\n}\n\n/**\n * IAM resource checker (roles and policies)\n */\nexport const IAMChecker: ResourceChecker = {\n async check(arn: ParsedArn): Promise<ResourceCheckResult> {\n const { resourceType, resourceId, raw } = arn;\n\n switch (resourceType) {\n case \"role\":\n return checkRole(resourceId, raw);\n case \"policy\":\n return checkPolicy(raw);\n default:\n return {\n arn: raw,\n exists: false,\n error: `Unsupported IAM resource type: ${resourceType}`,\n service: \"iam\",\n resourceType,\n resourceId,\n };\n }\n },\n};\n\n/**\n * Check if an IAM role exists\n */\nasync function checkRole(roleName: string, arn: string): Promise<ResourceCheckResult> {\n const iamClient = getClient();\n\n try {\n await iamClient.send(new GetRoleCommand({ RoleName: roleName }));\n return {\n arn,\n exists: true,\n service: \"iam\",\n resourceType: \"role\",\n resourceId: roleName,\n };\n } catch (error) {\n const err = error as Error & { name?: string };\n\n if (err.name === \"NoSuchEntityException\") {\n return {\n arn,\n exists: false,\n service: \"iam\",\n resourceType: \"role\",\n resourceId: roleName,\n };\n }\n\n return {\n arn,\n exists: false,\n error: err.message || \"Unknown error\",\n service: \"iam\",\n resourceType: \"role\",\n resourceId: roleName,\n };\n }\n}\n\n/**\n * Check if an IAM policy exists\n */\nasync function checkPolicy(policyArn: string): Promise<ResourceCheckResult> {\n const iamClient = getClient();\n\n // Extract policy name from ARN for display\n const policyName = policyArn.split(\"/\").pop() ?? policyArn;\n\n try {\n await iamClient.send(new GetPolicyCommand({ PolicyArn: policyArn }));\n return {\n arn: policyArn,\n exists: true,\n service: \"iam\",\n resourceType: \"policy\",\n resourceId: policyName,\n };\n } catch (error) {\n const err = error as Error & { name?: string };\n\n if (err.name === \"NoSuchEntityException\") {\n return {\n arn: policyArn,\n exists: false,\n service: \"iam\",\n resourceType: \"policy\",\n resourceId: policyName,\n };\n }\n\n return {\n arn: policyArn,\n exists: false,\n error: err.message || \"Unknown error\",\n service: \"iam\",\n resourceType: \"policy\",\n resourceId: policyName,\n };\n }\n}\n"],"mappings":";AAIA,SAAS,kBAAkB,gBAAgB,iBAAiB;AAQ5D,IAAI,SAA2B;AAK/B,SAAS,YAAuB;AAE9B,aAAW,IAAI,UAAU,EAAE,QAAQ,YAAY,CAAC;AAChD,SAAO;AACT;AAKO,IAAM,aAA8B;AAAA,EACzC,MAAM,MAAM,KAA8C;AACxD,UAAM,EAAE,cAAc,YAAY,IAAI,IAAI;AAE1C,YAAQ,cAAc;AAAA,MACpB,KAAK;AACH,eAAO,UAAU,YAAY,GAAG;AAAA,MAClC,KAAK;AACH,eAAO,YAAY,GAAG;AAAA,MACxB;AACE,eAAO;AAAA,UACL,KAAK;AAAA,UACL,QAAQ;AAAA,UACR,OAAO,kCAAkC,YAAY;AAAA,UACrD,SAAS;AAAA,UACT;AAAA,UACA;AAAA,QACF;AAAA,IACJ;AAAA,EACF;AACF;AAKA,eAAe,UAAU,UAAkB,KAA2C;AACpF,QAAM,YAAY,UAAU;AAE5B,MAAI;AACF,UAAM,UAAU,KAAK,IAAI,eAAe,EAAE,UAAU,SAAS,CAAC,CAAC;AAC/D,WAAO;AAAA,MACL;AAAA,MACA,QAAQ;AAAA,MACR,SAAS;AAAA,MACT,cAAc;AAAA,MACd,YAAY;AAAA,IACd;AAAA,EACF,SAAS,OAAO;AACd,UAAM,MAAM;AAEZ,QAAI,IAAI,SAAS,yBAAyB;AACxC,aAAO;AAAA,QACL;AAAA,QACA,QAAQ;AAAA,QACR,SAAS;AAAA,QACT,cAAc;AAAA,QACd,YAAY;AAAA,MACd;AAAA,IACF;AAEA,WAAO;AAAA,MACL;AAAA,MACA,QAAQ;AAAA,MACR,OAAO,IAAI,WAAW;AAAA,MACtB,SAAS;AAAA,MACT,cAAc;AAAA,MACd,YAAY;AAAA,IACd;AAAA,EACF;AACF;AAKA,eAAe,YAAY,WAAiD;AAC1E,QAAM,YAAY,UAAU;AAG5B,QAAM,aAAa,UAAU,MAAM,GAAG,EAAE,IAAI,KAAK;AAEjD,MAAI;AACF,UAAM,UAAU,KAAK,IAAI,iBAAiB,EAAE,WAAW,UAAU,CAAC,CAAC;AACnE,WAAO;AAAA,MACL,KAAK;AAAA,MACL,QAAQ;AAAA,MACR,SAAS;AAAA,MACT,cAAc;AAAA,MACd,YAAY;AAAA,IACd;AAAA,EACF,SAAS,OAAO;AACd,UAAM,MAAM;AAEZ,QAAI,IAAI,SAAS,yBAAyB;AACxC,aAAO;AAAA,QACL,KAAK;AAAA,QACL,QAAQ;AAAA,QACR,SAAS;AAAA,QACT,cAAc;AAAA,QACd,YAAY;AAAA,MACd;AAAA,IACF;AAEA,WAAO;AAAA,MACL,KAAK;AAAA,MACL,QAAQ;AAAA,MACR,OAAO,IAAI,WAAW;AAAA,MACtB,SAAS;AAAA,MACT,cAAc;AAAA,MACd,YAAY;AAAA,IACd;AAAA,EACF;AACF;","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/infra/checkers/lambda.ts"],"sourcesContent":["/**\n * Lambda resource checker\n */\n\nimport { GetFunctionCommand, LambdaClient } from \"@aws-sdk/client-lambda\";\n\nimport type { ParsedArn, ResourceCheckResult } from \"../types.js\";\nimport type { ResourceChecker } from \"./types.js\";\n\n/**\n * Cache of Lambda clients by region\n */\nconst clientCache = new Map<string, LambdaClient>();\n\n/**\n * Get or create a Lambda client for a region\n */\nfunction getClient(region: string): LambdaClient {\n let client = clientCache.get(region);\n if (!client) {\n client = new LambdaClient({ region });\n clientCache.set(region, client);\n }\n return client;\n}\n\n/**\n * Lambda function checker\n */\nexport const LambdaChecker: ResourceChecker = {\n async check(arn: ParsedArn): Promise<ResourceCheckResult> {\n const { resourceType, resourceId, region, raw } = arn;\n\n // Only check functions (not layers for now)\n if (resourceType !== \"function\") {\n return {\n arn: raw,\n exists: false,\n error: `Unsupported Lambda resource type: ${resourceType}`,\n service: \"lambda\",\n resourceType,\n resourceId,\n };\n }\n\n const client = getClient(region);\n\n try {\n await client.send(new GetFunctionCommand({ FunctionName: resourceId }));\n return {\n arn: raw,\n exists: true,\n service: \"lambda\",\n resourceType: \"function\",\n resourceId,\n };\n } catch (error) {\n const err = error as Error & { name?: string };\n\n if (err.name === \"ResourceNotFoundException\") {\n return {\n arn: raw,\n exists: false,\n service: \"lambda\",\n resourceType: \"function\",\n resourceId,\n };\n }\n\n return {\n arn: raw,\n exists: false,\n error: err.message || \"Unknown error\",\n service: \"lambda\",\n resourceType: \"function\",\n resourceId,\n };\n }\n },\n};\n"],"mappings":";AAIA,SAAS,oBAAoB,oBAAoB;AAQjD,IAAM,cAAc,oBAAI,IAA0B;AAKlD,SAAS,UAAU,QAA8B;AAC/C,MAAI,SAAS,YAAY,IAAI,MAAM;AACnC,MAAI,CAAC,QAAQ;AACX,aAAS,IAAI,aAAa,EAAE,OAAO,CAAC;AACpC,gBAAY,IAAI,QAAQ,MAAM;AAAA,EAChC;AACA,SAAO;AACT;AAKO,IAAM,gBAAiC;AAAA,EAC5C,MAAM,MAAM,KAA8C;AACxD,UAAM,EAAE,cAAc,YAAY,QAAQ,IAAI,IAAI;AAGlD,QAAI,iBAAiB,YAAY;AAC/B,aAAO;AAAA,QACL,KAAK;AAAA,QACL,QAAQ;AAAA,QACR,OAAO,qCAAqC,YAAY;AAAA,QACxD,SAAS;AAAA,QACT;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAEA,UAAM,SAAS,UAAU,MAAM;AAE/B,QAAI;AACF,YAAM,OAAO,KAAK,IAAI,mBAAmB,EAAE,cAAc,WAAW,CAAC,CAAC;AACtE,aAAO;AAAA,QACL,KAAK;AAAA,QACL,QAAQ;AAAA,QACR,SAAS;AAAA,QACT,cAAc;AAAA,QACd;AAAA,MACF;AAAA,IACF,SAAS,OAAO;AACd,YAAM,MAAM;AAEZ,UAAI,IAAI,SAAS,6BAA6B;AAC5C,eAAO;AAAA,UACL,KAAK;AAAA,UACL,QAAQ;AAAA,UACR,SAAS;AAAA,UACT,cAAc;AAAA,UACd;AAAA,QACF;AAAA,MACF;AAEA,aAAO;AAAA,QACL,KAAK;AAAA,QACL,QAAQ;AAAA,QACR,OAAO,IAAI,WAAW;AAAA,QACtB,SAAS;AAAA,QACT,cAAc;AAAA,QACd;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/infra/checkers/rds.ts"],"sourcesContent":["/**\n * RDS resource checker\n *\n * Supports:\n * - DB instances\n * - DB clusters (Aurora)\n * - DB subnet groups\n */\n\nimport {\n DescribeDBInstancesCommand,\n DescribeDBClustersCommand,\n DescribeDBSubnetGroupsCommand,\n RDSClient,\n} from \"@aws-sdk/client-rds\";\n\nimport type { ParsedArn, ResourceCheckResult } from \"../types.js\";\nimport type { ResourceChecker } from \"./types.js\";\n\n/**\n * Cache of RDS clients by region\n */\nconst clientCache = new Map<string, RDSClient>();\n\n/**\n * Get or create an RDS client for a region\n */\nfunction getClient(region: string): RDSClient {\n let client = clientCache.get(region);\n if (!client) {\n client = new RDSClient({ region });\n clientCache.set(region, client);\n }\n return client;\n}\n\n/**\n * Check if an RDS DB instance exists\n */\nasync function checkDBInstance(\n client: RDSClient,\n arn: ParsedArn\n): Promise<ResourceCheckResult> {\n const { resourceId, raw } = arn;\n\n try {\n const response = await client.send(\n new DescribeDBInstancesCommand({ DBInstanceIdentifier: resourceId })\n );\n\n const instance = response.DBInstances?.[0];\n const exists = !!instance && instance.DBInstanceStatus !== \"deleting\";\n\n return {\n arn: raw,\n exists,\n service: \"rds\",\n resourceType: \"db\",\n resourceId,\n };\n } catch (error) {\n const err = error as Error & { name?: string };\n\n if (err.name === \"DBInstanceNotFoundFault\") {\n return {\n arn: raw,\n exists: false,\n service: \"rds\",\n resourceType: \"db\",\n resourceId,\n };\n }\n\n return {\n arn: raw,\n exists: false,\n error: err.message || \"Unknown error\",\n service: \"rds\",\n resourceType: \"db\",\n resourceId,\n };\n }\n}\n\n/**\n * Check if an RDS DB cluster exists (Aurora)\n */\nasync function checkDBCluster(\n client: RDSClient,\n arn: ParsedArn\n): Promise<ResourceCheckResult> {\n const { resourceId, raw } = arn;\n\n try {\n const response = await client.send(\n new DescribeDBClustersCommand({ DBClusterIdentifier: resourceId })\n );\n\n const cluster = response.DBClusters?.[0];\n const exists = !!cluster && cluster.Status !== \"deleting\";\n\n return {\n arn: raw,\n exists,\n service: \"rds\",\n resourceType: \"cluster\",\n resourceId,\n };\n } catch (error) {\n const err = error as Error & { name?: string };\n\n if (err.name === \"DBClusterNotFoundFault\") {\n return {\n arn: raw,\n exists: false,\n service: \"rds\",\n resourceType: \"cluster\",\n resourceId,\n };\n }\n\n return {\n arn: raw,\n exists: false,\n error: err.message || \"Unknown error\",\n service: \"rds\",\n resourceType: \"cluster\",\n resourceId,\n };\n }\n}\n\n/**\n * Check if an RDS DB subnet group exists\n */\nasync function checkDBSubnetGroup(\n client: RDSClient,\n arn: ParsedArn\n): Promise<ResourceCheckResult> {\n const { resourceId, raw } = arn;\n\n try {\n const response = await client.send(\n new DescribeDBSubnetGroupsCommand({ DBSubnetGroupName: resourceId })\n );\n\n const subnetGroup = response.DBSubnetGroups?.[0];\n const exists = !!subnetGroup;\n\n return {\n arn: raw,\n exists,\n service: \"rds\",\n resourceType: \"subgrp\",\n resourceId,\n };\n } catch (error) {\n const err = error as Error & { name?: string };\n\n if (err.name === \"DBSubnetGroupNotFoundFault\") {\n return {\n arn: raw,\n exists: false,\n service: \"rds\",\n resourceType: \"subgrp\",\n resourceId,\n };\n }\n\n return {\n arn: raw,\n exists: false,\n error: err.message || \"Unknown error\",\n service: \"rds\",\n resourceType: \"subgrp\",\n resourceId,\n };\n }\n}\n\n/**\n * RDS resource checker\n */\nexport const RDSChecker: ResourceChecker = {\n async check(arn: ParsedArn): Promise<ResourceCheckResult> {\n const { resourceType, resourceId, region, raw } = arn;\n const client = getClient(region);\n\n switch (resourceType) {\n case \"db\":\n return checkDBInstance(client, arn);\n\n case \"cluster\":\n return checkDBCluster(client, arn);\n\n case \"subgrp\":\n return checkDBSubnetGroup(client, arn);\n\n default:\n return {\n arn: raw,\n exists: false,\n error: `Unsupported RDS resource type: ${resourceType}`,\n service: \"rds\",\n resourceType,\n resourceId,\n };\n }\n },\n};\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/infra/checkers/s3.ts"],"sourcesContent":["/**\n * S3 resource checker\n */\n\nimport { HeadBucketCommand, S3Client } from \"@aws-sdk/client-s3\";\n\nimport type { ParsedArn, ResourceCheckResult } from \"../types.js\";\nimport type { ResourceChecker } from \"./types.js\";\n\n/**\n * Cache of S3 clients by region\n */\nconst clientCache = new Map<string, S3Client>();\n\n/**\n * Get or create an S3 client for a region\n */\nfunction getClient(region: string): S3Client {\n // S3 is global, but we use us-east-1 for global operations\n const effectiveRegion = region || \"us-east-1\";\n\n let client = clientCache.get(effectiveRegion);\n if (!client) {\n client = new S3Client({\n region: effectiveRegion,\n followRegionRedirects: true,\n });\n clientCache.set(effectiveRegion, client);\n }\n return client;\n}\n\n/**\n * S3 bucket checker\n */\nexport const S3Checker: ResourceChecker = {\n async check(arn: ParsedArn): Promise<ResourceCheckResult> {\n const { resourceType, resourceId, raw } = arn;\n\n // Only check bucket existence (not individual objects)\n if (resourceType === \"object\") {\n // For objects, we'd need to check if the key exists, which is expensive\n // For now, we just check if the bucket exists\n const bucketName = resourceId.split(\"/\")[0];\n return checkBucket(bucketName, arn.region, raw);\n }\n\n return checkBucket(resourceId, arn.region, raw);\n },\n};\n\n/**\n * Create a bucket check result\n */\nfunction bucketResult(\n arn: string,\n bucketName: string,\n exists: boolean,\n error?: string\n): ResourceCheckResult {\n return { arn, exists, error, service: \"s3\", resourceType: \"bucket\", resourceId: bucketName };\n}\n\n/**\n * Check if error indicates bucket doesn't exist (404 or 403)\n */\nfunction isBucketNotFound(err: Error & { name?: string; $metadata?: { httpStatusCode?: number } }): boolean {\n const httpStatus = err.$metadata?.httpStatusCode;\n // 404 = not found, 403 = access denied (S3 returns 403 for non-existent buckets to prevent enumeration)\n return err.name === \"NotFound\" || err.name === \"NoSuchBucket\" || httpStatus === 404 ||\n err.name === \"Forbidden\" || err.name === \"AccessDenied\" || httpStatus === 403;\n}\n\n/**\n * Check if an S3 bucket exists\n */\nasync function checkBucket(bucketName: string, region: string, arn: string): Promise<ResourceCheckResult> {\n const client = getClient(region);\n\n try {\n await client.send(new HeadBucketCommand({ Bucket: bucketName }));\n return bucketResult(arn, bucketName, true);\n } catch (error) {\n const err = error as Error & { name?: string; $metadata?: { httpStatusCode?: number } };\n if (isBucketNotFound(err)) {\n return bucketResult(arn, bucketName, false);\n }\n return bucketResult(arn, bucketName, false, err.message || \"Unknown error\");\n }\n}\n"],"mappings":";AAIA,SAAS,mBAAmB,gBAAgB;AAQ5C,IAAM,cAAc,oBAAI,IAAsB;AAK9C,SAAS,UAAU,QAA0B;AAE3C,QAAM,kBAAkB,UAAU;AAElC,MAAI,SAAS,YAAY,IAAI,eAAe;AAC5C,MAAI,CAAC,QAAQ;AACX,aAAS,IAAI,SAAS;AAAA,MACpB,QAAQ;AAAA,MACR,uBAAuB;AAAA,IACzB,CAAC;AACD,gBAAY,IAAI,iBAAiB,MAAM;AAAA,EACzC;AACA,SAAO;AACT;AAKO,IAAM,YAA6B;AAAA,EACxC,MAAM,MAAM,KAA8C;AACxD,UAAM,EAAE,cAAc,YAAY,IAAI,IAAI;AAG1C,QAAI,iBAAiB,UAAU;AAG7B,YAAM,aAAa,WAAW,MAAM,GAAG,EAAE,CAAC;AAC1C,aAAO,YAAY,YAAY,IAAI,QAAQ,GAAG;AAAA,IAChD;AAEA,WAAO,YAAY,YAAY,IAAI,QAAQ,GAAG;AAAA,EAChD;AACF;AAKA,SAAS,aACP,KACA,YACA,QACA,OACqB;AACrB,SAAO,EAAE,KAAK,QAAQ,OAAO,SAAS,MAAM,cAAc,UAAU,YAAY,WAAW;AAC7F;AAKA,SAAS,iBAAiB,KAAkF;AAC1G,QAAM,aAAa,IAAI,WAAW;AAElC,SAAO,IAAI,SAAS,cAAc,IAAI,SAAS,kBAAkB,eAAe,OACzE,IAAI,SAAS,eAAe,IAAI,SAAS,kBAAkB,eAAe;AACnF;AAKA,eAAe,YAAY,YAAoB,QAAgB,KAA2C;AACxG,QAAM,SAAS,UAAU,MAAM;AAE/B,MAAI;AACF,UAAM,OAAO,KAAK,IAAI,kBAAkB,EAAE,QAAQ,WAAW,CAAC,CAAC;AAC/D,WAAO,aAAa,KAAK,YAAY,IAAI;AAAA,EAC3C,SAAS,OAAO;AACd,UAAM,MAAM;AACZ,QAAI,iBAAiB,GAAG,GAAG;AACzB,aAAO,aAAa,KAAK,YAAY,KAAK;AAAA,IAC5C;AACA,WAAO,aAAa,KAAK,YAAY,OAAO,IAAI,WAAW,eAAe;AAAA,EAC5E;AACF;","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/process/scan/index.ts","../src/process/scan/scanner.ts","../src/process/scan/remote-fetcher.ts","../src/process/scan/validators.ts"],"sourcesContent":["import chalk from \"chalk\";\n\nimport { loadConfigAsync } from \"../../core/index.js\";\nimport { ExitCode } from \"../../core/index.js\";\nimport { scanRepository } from \"./scanner.js\";\nimport { type ScanOptions, type ScanResult } from \"./types.js\";\n\n// Re-export public API types\nexport {\n type RemoteRepoInfo,\n type ScanOptions,\n type ScanResult,\n type ValidateProcessOptions,\n type ValidateProcessResult,\n} from \"./types.js\";\n\n// Re-export scanner\nexport { scanRepository, validateProcess } from \"./scanner.js\";\n\n/** Format scan result as text */\nfunction formatScanText(result: ScanResult): string {\n const lines: string[] = [];\n\n lines.push(`Repository: ${result.repoInfo.owner}/${result.repoInfo.repo}`);\n lines.push(\"\");\n\n for (const check of result.checks) {\n if (check.skipped) {\n lines.push(chalk.yellow(`⊘ ${check.name} (skipped: ${check.skipReason})`));\n } else if (check.passed) {\n lines.push(chalk.green(`✓ ${check.name}`));\n } else {\n lines.push(chalk.red(`✗ ${check.name}`));\n for (const violation of check.violations) {\n lines.push(chalk.red(` • ${violation.message}`));\n }\n }\n }\n\n lines.push(\"\");\n lines.push(\n `Summary: ${result.summary.passedChecks} passed, ` +\n `${result.summary.failedChecks} failed, ` +\n `${result.summary.skippedChecks} skipped`\n );\n\n return lines.join(\"\\n\");\n}\n\n/** Format scan result as JSON */\nfunction formatScanJson(result: ScanResult): string {\n return JSON.stringify(result, null, 2);\n}\n\n/** Run the scan command */\nexport async function runScan(options: ScanOptions): Promise<void> {\n try {\n const { config } = await loadConfigAsync(options.config);\n const result = await scanRepository(options.repo, config);\n\n const output = options.format === \"json\" ? formatScanJson(result) : formatScanText(result);\n\n process.stdout.write(`${output}\\n`);\n process.exit(result.passed ? ExitCode.SUCCESS : ExitCode.VIOLATIONS_FOUND);\n } catch (error) {\n if (options.format === \"json\") {\n const errorObj = {\n error: true,\n message: error instanceof Error ? error.message : String(error),\n code: (error as { code?: string }).code ?? \"UNKNOWN\",\n };\n process.stdout.write(`${JSON.stringify(errorObj, null, 2)}\\n`);\n } else {\n console.error(chalk.red(`Error: ${error instanceof Error ? error.message : String(error)}`));\n }\n process.exit(ExitCode.RUNTIME_ERROR);\n }\n}\n","import { execa } from \"execa\";\n\nimport { type Config } from \"../../core/index.js\";\nimport { type CheckResult, ExitCode, type Violation } from \"../../core/index.js\";\nimport {\n checkRemoteFiles,\n isGhAvailable,\n parseRepoString,\n RemoteFetcherError,\n standardFileChecks,\n verifyRepoAccess,\n} from \"./remote-fetcher.js\";\nimport {\n type FileCheckConfig,\n type RemoteRepoInfo,\n type ScanResult,\n type ValidateProcessOptions,\n type ValidateProcessResult,\n} from \"./types.js\";\nimport { type RulesetResponse, validateRulesets } from \"./validators.js\";\n\n/** Fetch rulesets from GitHub API */\nasync function fetchRulesets(repoInfo: RemoteRepoInfo): Promise<RulesetResponse[]> {\n const result = await execa(\"gh\", [\"api\", `repos/${repoInfo.owner}/${repoInfo.repo}/rulesets`]);\n return JSON.parse(result.stdout) as RulesetResponse[];\n}\n\n/** Create a skipped check result */\nfunction createSkippedResult(\n name: string,\n rule: string,\n reason: string,\n duration: number\n): CheckResult {\n return { name, rule, passed: true, violations: [], skipped: true, skipReason: reason, duration };\n}\n\n/** Create an error check result */\nfunction createErrorResult(\n name: string,\n rule: string,\n message: string,\n duration: number\n): CheckResult {\n return {\n name,\n rule,\n passed: false,\n violations: [{ rule, tool: \"scan\", message, severity: \"error\" }],\n skipped: false,\n duration,\n };\n}\n\n/** Handle API errors for ruleset fetching */\nfunction handleRulesetError(\n error: unknown,\n repoConfig: NonNullable<Config[\"process\"]>[\"repo\"],\n elapsed: () => number\n): CheckResult {\n const msg = error instanceof Error ? error.message : String(error);\n\n if (msg.includes(\"403\") || msg.includes(\"Must have admin rights\")) {\n return createSkippedResult(\n \"Repository Settings\",\n \"process.repo\",\n \"Cannot check rulesets: insufficient permissions (requires admin access)\",\n elapsed()\n );\n }\n\n if (msg.includes(\"404\")) {\n const violations: Violation[] = [];\n if (repoConfig?.require_branch_protection) {\n violations.push({\n rule: \"process.repo.branch_protection\",\n tool: \"scan\",\n message: \"No branch protection rulesets configured\",\n severity: \"error\",\n });\n }\n return {\n name: \"Repository Settings\",\n rule: \"process.repo\",\n passed: violations.length === 0,\n violations,\n skipped: false,\n duration: elapsed(),\n };\n }\n\n return createErrorResult(\n \"Repository Settings\",\n \"process.repo\",\n `Failed to check rulesets: ${msg}`,\n elapsed()\n );\n}\n\n/** Check repository rulesets and branch protection */\nasync function checkRulesets(repoInfo: RemoteRepoInfo, config: Config): Promise<CheckResult> {\n const startTime = Date.now();\n const elapsed = (): number => Date.now() - startTime;\n const repoConfig = config.process?.repo;\n\n if (!repoConfig?.enabled) {\n return createSkippedResult(\n \"Repository Settings\",\n \"process.repo\",\n \"Repository settings check not enabled in config\",\n elapsed()\n );\n }\n\n try {\n const rulesets = await fetchRulesets(repoInfo);\n const violations = validateRulesets(rulesets, repoConfig);\n\n return {\n name: \"Repository Settings\",\n rule: \"process.repo\",\n passed: violations.length === 0,\n violations,\n skipped: false,\n duration: elapsed(),\n };\n } catch (error) {\n return handleRulesetError(error, repoConfig, elapsed);\n }\n}\n\n/** Build file checks configuration from config */\nfunction buildFileChecks(config: Config): FileCheckConfig[] {\n const fileChecks: FileCheckConfig[] = [];\n\n if (config.process?.repo?.require_codeowners) {\n fileChecks.push({\n path: \"CODEOWNERS\",\n alternativePaths: [\".github/CODEOWNERS\", \"docs/CODEOWNERS\"],\n required: true,\n description: \"CODEOWNERS file for code review assignment\",\n });\n }\n\n fileChecks.push(\n ...standardFileChecks.filter((check) => !fileChecks.some((fc) => fc.path === check.path))\n );\n\n return fileChecks;\n}\n\n/** Convert file check results to violations */\nfunction fileResultsToViolations(\n results: { path: string; exists: boolean; checkedPaths: string[] }[],\n fileChecks: FileCheckConfig[]\n): Violation[] {\n const violations: Violation[] = [];\n\n for (const result of results) {\n const checkConfig = fileChecks.find((fc) => fc.path === result.path);\n if (!result.exists && checkConfig?.required) {\n violations.push({\n rule: `process.scan.files.${result.path.replace(/[./]/g, \"_\")}`,\n tool: \"scan\",\n message: `Required file not found: ${result.path} (checked: ${result.checkedPaths.join(\", \")})`,\n severity: \"error\",\n });\n }\n }\n\n return violations;\n}\n\n/** Check remote files for existence */\nasync function checkFiles(repoInfo: RemoteRepoInfo, config: Config): Promise<CheckResult> {\n const startTime = Date.now();\n const elapsed = (): number => Date.now() - startTime;\n const fileChecks = buildFileChecks(config);\n\n if (fileChecks.length === 0) {\n return createSkippedResult(\n \"Repository Files\",\n \"process.scan.files\",\n \"No file checks configured\",\n elapsed()\n );\n }\n\n try {\n const results = await checkRemoteFiles(repoInfo, fileChecks);\n const violations = fileResultsToViolations(results, fileChecks);\n\n return {\n name: \"Repository Files\",\n rule: \"process.scan.files\",\n passed: violations.length === 0,\n violations,\n skipped: false,\n duration: elapsed(),\n };\n } catch (error) {\n const msg = error instanceof Error ? error.message : String(error);\n return createErrorResult(\n \"Repository Files\",\n \"process.scan.files\",\n `Failed to check files: ${msg}`,\n elapsed()\n );\n }\n}\n\n/** Aggregate check results into scan result */\nfunction aggregateResults(repoInfo: RemoteRepoInfo, checks: CheckResult[]): ScanResult {\n const violations = checks.flatMap((c) => c.violations);\n const passedChecks = checks.filter((c) => c.passed && !c.skipped).length;\n const failedChecks = checks.filter((c) => !c.passed && !c.skipped).length;\n const skippedChecks = checks.filter((c) => c.skipped).length;\n\n return {\n repoInfo,\n checks,\n violations,\n passed: failedChecks === 0,\n summary: { totalChecks: checks.length, passedChecks, failedChecks, skippedChecks },\n };\n}\n\n/** Run all remote scans for a repository */\nexport async function scanRepository(repo: string, config: Config): Promise<ScanResult> {\n const repoInfo = parseRepoString(repo);\n\n if (!(await isGhAvailable())) {\n throw new RemoteFetcherError(\n \"GitHub CLI (gh) not available. Install it from https://cli.github.com/\",\n \"NO_GH\"\n );\n }\n\n await verifyRepoAccess(repoInfo);\n\n const [rulesetsResult, filesResult] = await Promise.all([\n checkRulesets(repoInfo, config),\n checkFiles(repoInfo, config),\n ]);\n\n return aggregateResults(repoInfo, [rulesetsResult, filesResult]);\n}\n\n/** Programmatic API for validating remote process checks */\nexport async function validateProcess(\n options: ValidateProcessOptions\n): Promise<ValidateProcessResult> {\n const { loadConfigAsync } = await import(\"../../core/index.js\");\n const { config } = await loadConfigAsync(options.config);\n const result = await scanRepository(options.repo, config);\n\n const fs = await import(\"node:fs\");\n const path = await import(\"node:path\");\n const { fileURLToPath } = await import(\"node:url\");\n\n const __dirname = path.dirname(fileURLToPath(import.meta.url));\n const packageJsonPath = path.resolve(__dirname, \"..\", \"..\", \"..\", \"package.json\");\n const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, \"utf-8\")) as { version: string };\n\n return {\n version: packageJson.version,\n repoInfo: result.repoInfo,\n domain: \"process\",\n checks: result.checks,\n summary: {\n totalChecks: result.summary.totalChecks,\n passedChecks: result.summary.passedChecks,\n failedChecks: result.summary.failedChecks,\n totalViolations: result.violations.length,\n exitCode: result.passed ? ExitCode.SUCCESS : ExitCode.VIOLATIONS_FOUND,\n },\n };\n}\n","import { execa } from \"execa\";\n\nimport { type FileCheckConfig, type FileCheckResult, type RemoteRepoInfo } from \"./types.js\";\n\n/** Error thrown when remote fetcher encounters an issue */\nexport class RemoteFetcherError extends Error {\n constructor(\n message: string,\n public readonly code: \"NO_GH\" | \"NO_REPO\" | \"NO_PERMISSION\" | \"API_ERROR\" | \"INVALID_REPO\"\n ) {\n super(message);\n this.name = \"RemoteFetcherError\";\n }\n}\n\n/** Parse owner/repo string into RemoteRepoInfo */\nexport function parseRepoString(repo: string): RemoteRepoInfo {\n const parts = repo.split(\"/\");\n if (parts.length !== 2 || !parts[0] || !parts[1]) {\n throw new RemoteFetcherError(\n `Invalid repository format: \"${repo}\". Expected \"owner/repo\" format.`,\n \"INVALID_REPO\"\n );\n }\n return { owner: parts[0], repo: parts[1] };\n}\n\n/** Check if gh CLI is available */\nexport async function isGhAvailable(): Promise<boolean> {\n try {\n await execa(\"gh\", [\"--version\"]);\n return true;\n } catch {\n return false;\n }\n}\n\n/** Verify the repository exists and user has access */\nexport async function verifyRepoAccess(repoInfo: RemoteRepoInfo): Promise<boolean> {\n try {\n await execa(\"gh\", [\"api\", `repos/${repoInfo.owner}/${repoInfo.repo}`]);\n return true;\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n\n if (errorMessage.includes(\"404\") || errorMessage.includes(\"Not Found\")) {\n throw new RemoteFetcherError(\n `Repository not found: ${repoInfo.owner}/${repoInfo.repo}`,\n \"NO_REPO\"\n );\n }\n\n if (errorMessage.includes(\"403\") || errorMessage.includes(\"401\")) {\n throw new RemoteFetcherError(\n `Cannot access repository: ${repoInfo.owner}/${repoInfo.repo}. Check your GITHUB_TOKEN permissions.`,\n \"NO_PERMISSION\"\n );\n }\n\n throw new RemoteFetcherError(\n `Failed to verify repository access: ${errorMessage}`,\n \"API_ERROR\"\n );\n }\n}\n\n/** Check if a file exists in the remote repository via GitHub Contents API */\nexport async function checkRemoteFileExists(\n repoInfo: RemoteRepoInfo,\n filePath: string\n): Promise<boolean> {\n try {\n await execa(\"gh\", [\n \"api\",\n `repos/${repoInfo.owner}/${repoInfo.repo}/contents/${filePath}`,\n \"--silent\",\n ]);\n return true;\n } catch {\n // File doesn't exist or no access - both return false\n return false;\n }\n}\n\n/** Check multiple alternative paths for a file */\nasync function checkRemoteFileWithAlternatives(\n repoInfo: RemoteRepoInfo,\n config: FileCheckConfig\n): Promise<FileCheckResult> {\n const allPaths = [config.path, ...(config.alternativePaths ?? [])];\n\n for (const path of allPaths) {\n // Sequential check needed - stop on first match\n const exists = await checkRemoteFileExists(repoInfo, path);\n if (exists) {\n return { path: config.path, exists: true, checkedPaths: allPaths };\n }\n }\n\n return { path: config.path, exists: false, checkedPaths: allPaths };\n}\n\n/** Batch check multiple files in a repository */\nexport async function checkRemoteFiles(\n repoInfo: RemoteRepoInfo,\n configs: FileCheckConfig[]\n): Promise<FileCheckResult[]> {\n // Run checks in parallel for efficiency\n const results = await Promise.all(\n configs.map((config) => checkRemoteFileWithAlternatives(repoInfo, config))\n );\n return results;\n}\n\n/** Standard file checks for remote validation */\nexport const standardFileChecks: FileCheckConfig[] = [\n {\n path: \"CODEOWNERS\",\n alternativePaths: [\".github/CODEOWNERS\", \"docs/CODEOWNERS\"],\n required: false,\n description: \"CODEOWNERS file for code review assignment\",\n },\n {\n path: \".github/PULL_REQUEST_TEMPLATE.md\",\n alternativePaths: [\n \".github/pull_request_template.md\",\n \"PULL_REQUEST_TEMPLATE.md\",\n \"pull_request_template.md\",\n ],\n required: false,\n description: \"Pull request template\",\n },\n {\n path: \"README.md\",\n alternativePaths: [\"readme.md\", \"README\"],\n required: false,\n description: \"Repository README\",\n },\n {\n path: \".github/workflows\",\n required: false,\n description: \"GitHub Actions workflows directory\",\n },\n];\n","import { type Config } from \"../../core/index.js\";\nimport { type Violation } from \"../../core/index.js\";\n\n/** GitHub Ruleset response types */\ninterface RulesetBypassActor {\n actor_id: number | null;\n actor_type: string;\n bypass_mode: string;\n}\n\ninterface RulesetRule {\n type: string;\n parameters?: {\n required_approving_review_count?: number;\n dismiss_stale_reviews_on_push?: boolean;\n require_code_owner_review?: boolean;\n required_status_checks?: { context: string }[];\n strict_required_status_checks_policy?: boolean;\n };\n}\n\nexport interface RulesetResponse {\n id: number;\n name: string;\n target: string;\n enforcement: string;\n conditions?: { ref_name?: { include?: string[]; exclude?: string[] } };\n bypass_actors?: RulesetBypassActor[];\n rules?: RulesetRule[];\n}\n\ntype RulesetConfig = NonNullable<NonNullable<Config[\"process\"]>[\"repo\"]>[\"ruleset\"];\ntype TagProtectionConfig = NonNullable<NonNullable<Config[\"process\"]>[\"repo\"]>[\"tag_protection\"];\n\n/** Check if branch matches any of the include patterns */\nfunction matchesBranch(patterns: string[], branch: string): boolean {\n for (const pattern of patterns) {\n const cleanPattern = pattern.replace(/^refs\\/heads\\//, \"\");\n if (cleanPattern === branch) {\n return true;\n }\n if (cleanPattern === \"~DEFAULT_BRANCH\" && branch === \"main\") {\n return true;\n }\n if (cleanPattern === \"~ALL\") {\n return true;\n }\n if (cleanPattern.includes(\"*\")) {\n const regex = new RegExp(`^${cleanPattern.replace(/\\*/g, \".*\")}$`);\n if (regex.test(branch)) {\n return true;\n }\n }\n }\n return false;\n}\n\n/** Find branch ruleset matching the target branch */\nfunction findBranchRuleset(\n rulesets: RulesetResponse[],\n branch: string\n): RulesetResponse | undefined {\n return rulesets.find(\n (r) =>\n r.target === \"branch\" &&\n r.enforcement === \"active\" &&\n matchesBranch(r.conditions?.ref_name?.include ?? [], branch)\n );\n}\n\n/** Validate rulesets against config */\n// eslint-disable-next-line complexity\nexport function validateRulesets(\n rulesets: RulesetResponse[],\n repoConfig: NonNullable<Config[\"process\"]>[\"repo\"]\n): Violation[] {\n if (!repoConfig) {\n return [];\n }\n\n const violations: Violation[] = [];\n const rulesetConfig = repoConfig.ruleset;\n const branch = rulesetConfig?.branch ?? \"main\";\n const branchRuleset = findBranchRuleset(rulesets, branch);\n\n if (repoConfig.require_branch_protection && !branchRuleset) {\n violations.push({\n rule: \"process.repo.branch_protection\",\n tool: \"scan\",\n message: `Branch '${branch}' does not have a branch protection ruleset`,\n severity: \"error\",\n });\n }\n\n if (branchRuleset && rulesetConfig) {\n violations.push(...validateBranchRuleset(branchRuleset, rulesetConfig, branch));\n }\n\n if (repoConfig.tag_protection?.patterns?.length) {\n violations.push(...validateTagProtection(rulesets, repoConfig.tag_protection));\n }\n\n return violations;\n}\n\n/** Validate branch ruleset settings against config */\nfunction validateBranchRuleset(\n ruleset: RulesetResponse,\n config: RulesetConfig,\n branch: string\n): Violation[] {\n if (!config) {\n return [];\n }\n\n const violations: Violation[] = [];\n const rules = ruleset.rules ?? [];\n const prRule = rules.find((r) => r.type === \"pull_request\");\n const statusRule = rules.find((r) => r.type === \"required_status_checks\");\n\n violations.push(...validatePullRequestRule(prRule, config, branch));\n violations.push(...validateStatusChecksRule(statusRule, config, branch));\n violations.push(...validateSignedCommits(rules, config, branch));\n violations.push(...validateBypassActors(ruleset.bypass_actors ?? [], config, branch));\n\n return violations;\n}\n\n/** Validate pull request rule settings */\n// eslint-disable-next-line complexity\nfunction validatePullRequestRule(\n prRule: RulesetRule | undefined,\n config: RulesetConfig,\n branch: string\n): Violation[] {\n if (!config) {\n return [];\n }\n\n const violations: Violation[] = [];\n const params = prRule?.parameters;\n\n if (config.required_reviews !== undefined) {\n const actualReviews = params?.required_approving_review_count ?? 0;\n if (actualReviews < config.required_reviews) {\n violations.push({\n rule: \"process.repo.branch_protection.required_reviews\",\n tool: \"scan\",\n message: `Branch '${branch}' requires ${actualReviews} reviews, expected at least ${config.required_reviews}`,\n severity: \"error\",\n });\n }\n }\n\n if (config.dismiss_stale_reviews === true && !(params?.dismiss_stale_reviews_on_push ?? false)) {\n violations.push({\n rule: \"process.repo.branch_protection.dismiss_stale_reviews\",\n tool: \"scan\",\n message: `Branch '${branch}' does not dismiss stale reviews on new commits`,\n severity: \"error\",\n });\n }\n\n if (config.require_code_owner_reviews === true && !(params?.require_code_owner_review ?? false)) {\n violations.push({\n rule: \"process.repo.branch_protection.require_code_owner_reviews\",\n tool: \"scan\",\n message: `Branch '${branch}' does not require code owner reviews`,\n severity: \"error\",\n });\n }\n\n return violations;\n}\n\n/** Validate status checks rule settings */\n// eslint-disable-next-line complexity\nfunction validateStatusChecksRule(\n statusRule: RulesetRule | undefined,\n config: RulesetConfig,\n branch: string\n): Violation[] {\n if (!config) {\n return [];\n }\n\n const violations: Violation[] = [];\n const params = statusRule?.parameters;\n\n if (config.require_status_checks && config.require_status_checks.length > 0) {\n const actualChecks = params?.required_status_checks?.map((c) => c.context) ?? [];\n const missingChecks = config.require_status_checks.filter(\n (check) => !actualChecks.includes(check)\n );\n if (missingChecks.length > 0) {\n violations.push({\n rule: \"process.repo.branch_protection.require_status_checks\",\n tool: \"scan\",\n message: `Branch '${branch}' missing required status checks: ${missingChecks.join(\", \")}`,\n severity: \"error\",\n });\n }\n }\n\n if (\n config.require_branches_up_to_date === true &&\n !(params?.strict_required_status_checks_policy ?? false)\n ) {\n violations.push({\n rule: \"process.repo.branch_protection.require_branches_up_to_date\",\n tool: \"scan\",\n message: `Branch '${branch}' does not require branches to be up to date before merging`,\n severity: \"error\",\n });\n }\n\n return violations;\n}\n\n/** Validate signed commits requirement */\nfunction validateSignedCommits(\n rules: RulesetRule[],\n config: RulesetConfig,\n branch: string\n): Violation[] {\n if (config?.require_signed_commits !== true) {\n return [];\n }\n\n if (!rules.some((r) => r.type === \"required_signatures\")) {\n return [\n {\n rule: \"process.repo.branch_protection.require_signed_commits\",\n tool: \"scan\",\n message: `Branch '${branch}' does not require signed commits`,\n severity: \"error\",\n },\n ];\n }\n\n return [];\n}\n\n/** Validate bypass actors configuration */\nfunction validateBypassActors(\n actualBypass: RulesetBypassActor[],\n config: RulesetConfig,\n branch: string\n): Violation[] {\n if (config?.enforce_admins !== true || actualBypass.length === 0) {\n return [];\n }\n\n return [\n {\n rule: \"process.repo.branch_protection.enforce_admins\",\n tool: \"scan\",\n message: `Branch '${branch}' has bypass actors configured but enforce_admins requires no bypasses`,\n severity: \"error\",\n },\n ];\n}\n\n/** Validate tag protection rulesets */\nfunction validateTagProtection(\n rulesets: RulesetResponse[],\n tagConfig: TagProtectionConfig\n): Violation[] {\n if (!tagConfig?.patterns?.length) {\n return [];\n }\n\n const violations: Violation[] = [];\n const tagRuleset = rulesets.find((r) => r.target === \"tag\" && r.enforcement === \"active\");\n\n if (!tagRuleset) {\n return [\n {\n rule: \"process.repo.tag_protection\",\n tool: \"scan\",\n message: \"No active tag protection ruleset found\",\n severity: \"error\",\n },\n ];\n }\n\n violations.push(...validateTagPatterns(tagConfig.patterns, tagRuleset));\n violations.push(...validateTagRules(tagConfig, tagRuleset.rules ?? []));\n\n return violations;\n}\n\n/** Validate tag patterns match */\nfunction validateTagPatterns(expectedPatterns: string[], tagRuleset: RulesetResponse): Violation[] {\n const expected = expectedPatterns.map((p) => `refs/tags/${p}`).sort();\n const actual = [...(tagRuleset.conditions?.ref_name?.include ?? [])].sort();\n\n if (expected.length === actual.length && expected.every((v, i) => v === actual[i])) {\n return [];\n }\n\n const found = actual.map((p) => p.replace(/^refs\\/tags\\//, \"\")).join(\", \");\n return [\n {\n rule: \"process.repo.tag_protection.patterns\",\n tool: \"scan\",\n message: `Tag protection patterns mismatch: expected [${expectedPatterns.join(\", \")}], found [${found}]`,\n severity: \"error\",\n },\n ];\n}\n\n/** Validate tag protection rules */\nfunction validateTagRules(tagConfig: TagProtectionConfig, rules: RulesetRule[]): Violation[] {\n if (!tagConfig) {\n return [];\n }\n\n const violations: Violation[] = [];\n\n if (tagConfig.prevent_deletion !== false && !rules.some((r) => r.type === \"deletion\")) {\n violations.push({\n rule: \"process.repo.tag_protection.prevent_deletion\",\n tool: \"scan\",\n message: \"Tag protection does not prevent deletion\",\n severity: \"error\",\n });\n }\n\n if (tagConfig.prevent_update !== false && !rules.some((r) => r.type === \"update\")) {\n violations.push({\n rule: \"process.repo.tag_protection.prevent_update\",\n tool: \"scan\",\n message: \"Tag protection does not prevent updates (force-push)\",\n severity: \"error\",\n });\n }\n\n return violations;\n}\n"],"mappings":"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","names":["execa","execa","loadConfigAsync"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/infra/checkers/secretsmanager.ts"],"sourcesContent":["/**\n * Secrets Manager resource checker\n */\n\nimport { DescribeSecretCommand, SecretsManagerClient } from \"@aws-sdk/client-secrets-manager\";\n\nimport type { ParsedArn, ResourceCheckResult } from \"../types.js\";\nimport type { ResourceChecker } from \"./types.js\";\n\n/**\n * Cache of Secrets Manager clients by region\n */\nconst clientCache = new Map<string, SecretsManagerClient>();\n\n/**\n * Get or create a Secrets Manager client for a region\n */\nfunction getClient(region: string): SecretsManagerClient {\n let client = clientCache.get(region);\n if (!client) {\n client = new SecretsManagerClient({ region });\n clientCache.set(region, client);\n }\n return client;\n}\n\n/**\n * Secrets Manager secret checker\n */\nexport const SecretsManagerChecker: ResourceChecker = {\n async check(arn: ParsedArn): Promise<ResourceCheckResult> {\n const { resourceId, region, raw } = arn;\n\n const client = getClient(region);\n\n try {\n // Use the full ARN to get the secret\n await client.send(new DescribeSecretCommand({ SecretId: raw }));\n\n return {\n arn: raw,\n exists: true,\n service: \"secretsmanager\",\n resourceType: \"secret\",\n resourceId,\n };\n } catch (error) {\n const err = error as Error & { name?: string };\n\n if (err.name === \"ResourceNotFoundException\") {\n return {\n arn: raw,\n exists: false,\n service: \"secretsmanager\",\n resourceType: \"secret\",\n resourceId,\n };\n }\n\n return {\n arn: raw,\n exists: false,\n error: err.message || \"Unknown error\",\n service: \"secretsmanager\",\n resourceType: \"secret\",\n resourceId,\n };\n }\n },\n};\n"],"mappings":";AAIA,SAAS,uBAAuB,4BAA4B;AAQ5D,IAAM,cAAc,oBAAI,IAAkC;AAK1D,SAAS,UAAU,QAAsC;AACvD,MAAI,SAAS,YAAY,IAAI,MAAM;AACnC,MAAI,CAAC,QAAQ;AACX,aAAS,IAAI,qBAAqB,EAAE,OAAO,CAAC;AAC5C,gBAAY,IAAI,QAAQ,MAAM;AAAA,EAChC;AACA,SAAO;AACT;AAKO,IAAM,wBAAyC;AAAA,EACpD,MAAM,MAAM,KAA8C;AACxD,UAAM,EAAE,YAAY,QAAQ,IAAI,IAAI;AAEpC,UAAM,SAAS,UAAU,MAAM;AAE/B,QAAI;AAEF,YAAM,OAAO,KAAK,IAAI,sBAAsB,EAAE,UAAU,IAAI,CAAC,CAAC;AAE9D,aAAO;AAAA,QACL,KAAK;AAAA,QACL,QAAQ;AAAA,QACR,SAAS;AAAA,QACT,cAAc;AAAA,QACd;AAAA,MACF;AAAA,IACF,SAAS,OAAO;AACd,YAAM,MAAM;AAEZ,UAAI,IAAI,SAAS,6BAA6B;AAC5C,eAAO;AAAA,UACL,KAAK;AAAA,UACL,QAAQ;AAAA,UACR,SAAS;AAAA,UACT,cAAc;AAAA,UACd;AAAA,QACF;AAAA,MACF;AAEA,aAAO;AAAA,QACL,KAAK;AAAA,QACL,QAAQ;AAAA,QACR,OAAO,IAAI,WAAW;AAAA,QACtB,SAAS;AAAA,QACT,cAAc;AAAA,QACd;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/infra/checkers/sns.ts"],"sourcesContent":["/**\n * SNS resource checker\n */\n\nimport { GetTopicAttributesCommand, SNSClient } from \"@aws-sdk/client-sns\";\n\nimport type { ParsedArn, ResourceCheckResult } from \"../types.js\";\nimport type { ResourceChecker } from \"./types.js\";\n\n/**\n * Cache of SNS clients by region\n */\nconst clientCache = new Map<string, SNSClient>();\n\n/**\n * Get or create an SNS client for a region\n */\nfunction getClient(region: string): SNSClient {\n let client = clientCache.get(region);\n if (!client) {\n client = new SNSClient({ region });\n clientCache.set(region, client);\n }\n return client;\n}\n\n/**\n * SNS topic checker\n */\nexport const SNSChecker: ResourceChecker = {\n async check(arn: ParsedArn): Promise<ResourceCheckResult> {\n const { resourceId, region, raw } = arn;\n\n const client = getClient(region);\n\n try {\n // Use the full ARN to get topic attributes\n await client.send(new GetTopicAttributesCommand({ TopicArn: raw }));\n\n return {\n arn: raw,\n exists: true,\n service: \"sns\",\n resourceType: \"topic\",\n resourceId,\n };\n } catch (error) {\n const err = error as Error & { name?: string };\n\n if (err.name === \"NotFoundException\" || err.name === \"NotFound\") {\n return {\n arn: raw,\n exists: false,\n service: \"sns\",\n resourceType: \"topic\",\n resourceId,\n };\n }\n\n return {\n arn: raw,\n exists: false,\n error: err.message || \"Unknown error\",\n service: \"sns\",\n resourceType: \"topic\",\n resourceId,\n };\n }\n },\n};\n"],"mappings":";AAIA,SAAS,2BAA2B,iBAAiB;AAQrD,IAAM,cAAc,oBAAI,IAAuB;AAK/C,SAAS,UAAU,QAA2B;AAC5C,MAAI,SAAS,YAAY,IAAI,MAAM;AACnC,MAAI,CAAC,QAAQ;AACX,aAAS,IAAI,UAAU,EAAE,OAAO,CAAC;AACjC,gBAAY,IAAI,QAAQ,MAAM;AAAA,EAChC;AACA,SAAO;AACT;AAKO,IAAM,aAA8B;AAAA,EACzC,MAAM,MAAM,KAA8C;AACxD,UAAM,EAAE,YAAY,QAAQ,IAAI,IAAI;AAEpC,UAAM,SAAS,UAAU,MAAM;AAE/B,QAAI;AAEF,YAAM,OAAO,KAAK,IAAI,0BAA0B,EAAE,UAAU,IAAI,CAAC,CAAC;AAElE,aAAO;AAAA,QACL,KAAK;AAAA,QACL,QAAQ;AAAA,QACR,SAAS;AAAA,QACT,cAAc;AAAA,QACd;AAAA,MACF;AAAA,IACF,SAAS,OAAO;AACd,YAAM,MAAM;AAEZ,UAAI,IAAI,SAAS,uBAAuB,IAAI,SAAS,YAAY;AAC/D,eAAO;AAAA,UACL,KAAK;AAAA,UACL,QAAQ;AAAA,UACR,SAAS;AAAA,UACT,cAAc;AAAA,UACd;AAAA,QACF;AAAA,MACF;AAEA,aAAO;AAAA,QACL,KAAK;AAAA,QACL,QAAQ;AAAA,QACR,OAAO,IAAI,WAAW;AAAA,QACtB,SAAS;AAAA,QACT,cAAc;AAAA,QACd;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/infra/checkers/sqs.ts"],"sourcesContent":["/**\n * SQS resource checker\n */\n\nimport { GetQueueAttributesCommand, GetQueueUrlCommand, SQSClient } from \"@aws-sdk/client-sqs\";\n\nimport type { ParsedArn, ResourceCheckResult } from \"../types.js\";\nimport type { ResourceChecker } from \"./types.js\";\n\n/**\n * Cache of SQS clients by region\n */\nconst clientCache = new Map<string, SQSClient>();\n\n/**\n * Get or create an SQS client for a region\n */\nfunction getClient(region: string): SQSClient {\n let client = clientCache.get(region);\n if (!client) {\n client = new SQSClient({ region });\n clientCache.set(region, client);\n }\n return client;\n}\n\n/**\n * SQS queue checker\n */\nexport const SQSChecker: ResourceChecker = {\n async check(arn: ParsedArn): Promise<ResourceCheckResult> {\n const { resourceId, region, accountId, raw } = arn;\n\n const client = getClient(region);\n\n try {\n // First, get the queue URL from the queue name and account ID\n const urlResponse = await client.send(\n new GetQueueUrlCommand({\n QueueName: resourceId,\n QueueOwnerAWSAccountId: accountId || undefined,\n })\n );\n\n // Then verify the queue exists by getting its attributes\n await client.send(\n new GetQueueAttributesCommand({\n QueueUrl: urlResponse.QueueUrl,\n AttributeNames: [\"QueueArn\"],\n })\n );\n\n return {\n arn: raw,\n exists: true,\n service: \"sqs\",\n resourceType: \"queue\",\n resourceId,\n };\n } catch (error) {\n const err = error as Error & { name?: string };\n\n if (\n err.name === \"QueueDoesNotExist\" ||\n err.name === \"AWS.SimpleQueueService.NonExistentQueue\"\n ) {\n return {\n arn: raw,\n exists: false,\n service: \"sqs\",\n resourceType: \"queue\",\n resourceId,\n };\n }\n\n return {\n arn: raw,\n exists: false,\n error: err.message || \"Unknown error\",\n service: \"sqs\",\n resourceType: \"queue\",\n resourceId,\n };\n }\n },\n};\n"],"mappings":";AAIA,SAAS,2BAA2B,oBAAoB,iBAAiB;AAQzE,IAAM,cAAc,oBAAI,IAAuB;AAK/C,SAAS,UAAU,QAA2B;AAC5C,MAAI,SAAS,YAAY,IAAI,MAAM;AACnC,MAAI,CAAC,QAAQ;AACX,aAAS,IAAI,UAAU,EAAE,OAAO,CAAC;AACjC,gBAAY,IAAI,QAAQ,MAAM;AAAA,EAChC;AACA,SAAO;AACT;AAKO,IAAM,aAA8B;AAAA,EACzC,MAAM,MAAM,KAA8C;AACxD,UAAM,EAAE,YAAY,QAAQ,WAAW,IAAI,IAAI;AAE/C,UAAM,SAAS,UAAU,MAAM;AAE/B,QAAI;AAEF,YAAM,cAAc,MAAM,OAAO;AAAA,QAC/B,IAAI,mBAAmB;AAAA,UACrB,WAAW;AAAA,UACX,wBAAwB,aAAa;AAAA,QACvC,CAAC;AAAA,MACH;AAGA,YAAM,OAAO;AAAA,QACX,IAAI,0BAA0B;AAAA,UAC5B,UAAU,YAAY;AAAA,UACtB,gBAAgB,CAAC,UAAU;AAAA,QAC7B,CAAC;AAAA,MACH;AAEA,aAAO;AAAA,QACL,KAAK;AAAA,QACL,QAAQ;AAAA,QACR,SAAS;AAAA,QACT,cAAc;AAAA,QACd;AAAA,MACF;AAAA,IACF,SAAS,OAAO;AACd,YAAM,MAAM;AAEZ,UACE,IAAI,SAAS,uBACb,IAAI,SAAS,2CACb;AACA,eAAO;AAAA,UACL,KAAK;AAAA,UACL,QAAQ;AAAA,UACR,SAAS;AAAA,UACT,cAAc;AAAA,UACd;AAAA,QACF;AAAA,MACF;AAEA,aAAO;AAAA,QACL,KAAK;AAAA,QACL,QAAQ;AAAA,QACR,OAAO,IAAI,WAAW;AAAA,QACtB,SAAS;AAAA,QACT,cAAc;AAAA,QACd;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/process/sync/applier.ts","../src/process/sync/differ.ts","../src/process/sync/fetcher.ts","../src/process/sync/index.ts"],"sourcesContent":["import { execa } from \"execa\";\n\nimport {\n type DesiredBranchProtection,\n type DesiredTagProtection,\n type RepoInfo,\n type SettingDiff,\n type SyncDiffResult,\n type SyncResult,\n type TagProtectionDiffResult,\n} from \"./types.js\";\n\n/** Error thrown when applier encounters an issue */\nexport class ApplierError extends Error {\n constructor(\n message: string,\n public readonly code: \"NO_PERMISSION\" | \"API_ERROR\"\n ) {\n super(message);\n this.name = \"ApplierError\";\n }\n}\n\n/** Apply branch protection ruleset to GitHub */\nexport async function applyBranchProtection(\n repoInfo: RepoInfo,\n branch: string,\n desired: DesiredBranchProtection,\n diffResult: SyncDiffResult\n): Promise<SyncResult> {\n if (!diffResult.hasChanges) {\n return { success: true, applied: [], failed: [] };\n }\n\n const requestBody = buildBranchRulesetBody(branch, desired);\n\n try {\n if (diffResult.currentRulesetId === null) {\n // Create new ruleset\n await execa(\n \"gh\",\n [\"api\", `repos/${repoInfo.owner}/${repoInfo.repo}/rulesets`, \"-X\", \"POST\", \"--input\", \"-\"],\n { input: JSON.stringify(requestBody) }\n );\n } else {\n // Update existing ruleset\n await execa(\n \"gh\",\n [\n \"api\",\n `repos/${repoInfo.owner}/${repoInfo.repo}/rulesets/${diffResult.currentRulesetId}`,\n \"-X\",\n \"PUT\",\n \"--input\",\n \"-\",\n ],\n { input: JSON.stringify(requestBody) }\n );\n }\n\n return { success: true, applied: diffResult.diffs, failed: [] };\n } catch (error) {\n return handleBranchApplyError(error, diffResult.diffs);\n }\n}\n\n/** Handle errors from applying branch protection */\nfunction handleBranchApplyError(error: unknown, diffs: SettingDiff[]): SyncResult {\n const errorMessage = error instanceof Error ? error.message : String(error);\n\n if (errorMessage.includes(\"403\") || errorMessage.includes(\"Must have admin rights\")) {\n throw new ApplierError(\n \"Cannot update branch protection: insufficient permissions (requires admin access)\",\n \"NO_PERMISSION\"\n );\n }\n\n return {\n success: false,\n applied: [],\n failed: diffs.map((diff) => ({ diff, error: errorMessage })),\n };\n}\n\n/** Build GitHub API request body for branch ruleset */\nfunction buildBranchRulesetBody(\n branch: string,\n desired: DesiredBranchProtection\n): Record<string, unknown> {\n const rules: { type: string; parameters?: Record<string, unknown> }[] = [];\n\n // Build pull_request rule if any review settings specified\n const pullRequestRule = buildPullRequestRule(desired);\n if (pullRequestRule) {\n rules.push(pullRequestRule);\n }\n\n // Build required_status_checks rule\n const statusChecksRule = buildStatusChecksRule(desired);\n if (statusChecksRule) {\n rules.push(statusChecksRule);\n }\n\n // Build required_signatures rule\n if (desired.require_signed_commits === true) {\n rules.push({ type: \"required_signatures\" });\n }\n\n // Build bypass actors array\n const bypassActors =\n desired.bypass_actors?.map((actor) => ({\n actor_id: actor.actor_id ?? null,\n actor_type: actor.actor_type,\n bypass_mode: actor.bypass_mode ?? \"always\",\n })) ?? [];\n\n return {\n name: \"Branch Protection\",\n target: \"branch\",\n enforcement: \"active\",\n conditions: {\n ref_name: {\n include: [`refs/heads/${branch}`],\n exclude: [],\n },\n },\n bypass_actors: bypassActors,\n rules,\n };\n}\n\n/** Build pull_request rule for PR review settings */\nfunction buildPullRequestRule(\n desired: DesiredBranchProtection\n): { type: string; parameters: Record<string, unknown> } | null {\n const hasReviewSettings =\n desired.required_reviews !== undefined ||\n desired.dismiss_stale_reviews !== undefined ||\n desired.require_code_owner_reviews !== undefined;\n\n if (!hasReviewSettings) {\n return null;\n }\n\n return {\n type: \"pull_request\",\n parameters: {\n ...(desired.required_reviews !== undefined && {\n required_approving_review_count: desired.required_reviews,\n }),\n ...(desired.dismiss_stale_reviews !== undefined && {\n dismiss_stale_reviews_on_push: desired.dismiss_stale_reviews,\n }),\n ...(desired.require_code_owner_reviews !== undefined && {\n require_code_owner_review: desired.require_code_owner_reviews,\n }),\n },\n };\n}\n\n/** Build required_status_checks rule for status check settings */\nfunction buildStatusChecksRule(\n desired: DesiredBranchProtection\n): { type: string; parameters: Record<string, unknown> } | null {\n const hasStatusSettings =\n desired.require_status_checks !== undefined ||\n desired.require_branches_up_to_date !== undefined;\n\n if (!hasStatusSettings) {\n return null;\n }\n\n const statusChecks =\n desired.require_status_checks?.map((context) => ({\n context,\n })) ?? [];\n\n return {\n type: \"required_status_checks\",\n parameters: {\n required_status_checks: statusChecks,\n strict_required_status_checks_policy: desired.require_branches_up_to_date ?? false,\n },\n };\n}\n\n// =============================================================================\n// Tag Protection (GitHub Rulesets API)\n// =============================================================================\n\n/** Apply tag protection ruleset to GitHub */\nexport async function applyTagProtection(\n repoInfo: RepoInfo,\n desired: DesiredTagProtection,\n diffResult: TagProtectionDiffResult\n): Promise<SyncResult> {\n if (!diffResult.hasChanges) {\n return { success: true, applied: [], failed: [] };\n }\n\n const requestBody = buildTagRulesetBody(desired);\n\n try {\n if (diffResult.currentRulesetId === null) {\n // Create new ruleset\n await execa(\n \"gh\",\n [\"api\", `repos/${repoInfo.owner}/${repoInfo.repo}/rulesets`, \"-X\", \"POST\", \"--input\", \"-\"],\n { input: JSON.stringify(requestBody) }\n );\n } else {\n // Update existing ruleset\n await execa(\n \"gh\",\n [\n \"api\",\n `repos/${repoInfo.owner}/${repoInfo.repo}/rulesets/${diffResult.currentRulesetId}`,\n \"-X\",\n \"PUT\",\n \"--input\",\n \"-\",\n ],\n { input: JSON.stringify(requestBody) }\n );\n }\n\n return { success: true, applied: diffResult.diffs, failed: [] };\n } catch (error) {\n return handleTagApplyError(error, diffResult.diffs);\n }\n}\n\n/** Build GitHub API request body for tag ruleset */\nfunction buildTagRulesetBody(desired: DesiredTagProtection): Record<string, unknown> {\n const rules: { type: string }[] = [];\n\n // Default to true if not specified\n if (desired.prevent_deletion !== false) {\n rules.push({ type: \"deletion\" });\n }\n if (desired.prevent_update !== false) {\n rules.push({ type: \"update\" });\n }\n\n const patterns = desired.patterns ?? [\"v*\"];\n const includePatterns = patterns.map((p) => `refs/tags/${p}`);\n\n return {\n name: \"Tag Protection\",\n target: \"tag\",\n enforcement: \"active\",\n conditions: {\n ref_name: {\n include: includePatterns,\n exclude: [],\n },\n },\n rules,\n };\n}\n\n/** Handle errors from applying tag protection */\nfunction handleTagApplyError(error: unknown, diffs: SettingDiff[]): SyncResult {\n const errorMessage = error instanceof Error ? error.message : String(error);\n\n if (errorMessage.includes(\"403\") || errorMessage.includes(\"Must have admin rights\")) {\n throw new ApplierError(\n \"Cannot update tag protection: insufficient permissions (requires admin access)\",\n \"NO_PERMISSION\"\n );\n }\n\n return {\n success: false,\n applied: [],\n failed: diffs.map((diff) => ({ diff, error: errorMessage })),\n };\n}\n","import {\n type BranchProtectionSettings,\n type BypassActor,\n type DesiredBranchProtection,\n type DesiredTagProtection,\n type RepoInfo,\n type SettingDiff,\n type SyncDiffResult,\n type TagProtectionDiffResult,\n type TagProtectionSettings,\n} from \"./types.js\";\n\n/** Field mapping for comparison */\ninterface FieldMapping {\n name: string;\n getCurrentValue: (c: BranchProtectionSettings) => unknown;\n getDesiredValue: (d: DesiredBranchProtection) => unknown;\n isArray?: boolean;\n}\n\n/** All field mappings for branch protection settings */\nconst fieldMappings: FieldMapping[] = [\n {\n name: \"required_reviews\",\n getCurrentValue: (c) => c.requiredReviews,\n getDesiredValue: (d) => d.required_reviews,\n },\n {\n name: \"dismiss_stale_reviews\",\n getCurrentValue: (c) => c.dismissStaleReviews,\n getDesiredValue: (d) => d.dismiss_stale_reviews,\n },\n {\n name: \"require_code_owner_reviews\",\n getCurrentValue: (c) => c.requireCodeOwnerReviews,\n getDesiredValue: (d) => d.require_code_owner_reviews,\n },\n {\n name: \"require_status_checks\",\n getCurrentValue: (c) => c.requiredStatusChecks,\n getDesiredValue: (d) => d.require_status_checks,\n isArray: true,\n },\n {\n name: \"require_branches_up_to_date\",\n getCurrentValue: (c) => c.requireBranchesUpToDate,\n getDesiredValue: (d) => d.require_branches_up_to_date,\n },\n {\n name: \"require_signed_commits\",\n getCurrentValue: (c) => c.requireSignedCommits,\n getDesiredValue: (d) => d.require_signed_commits,\n },\n {\n name: \"enforce_admins\",\n getCurrentValue: (c) => c.enforceAdmins,\n getDesiredValue: (d) => d.enforce_admins,\n },\n];\n\n/** Compare current settings with desired and generate diffs */\nexport function computeDiff(\n repoInfo: RepoInfo,\n current: BranchProtectionSettings,\n desired: DesiredBranchProtection\n): SyncDiffResult {\n const diffs = collectDiffs(current, desired);\n\n // Add bypass_actors diff\n const bypassDiff = compareBypassActors(\n current.bypassActors,\n desired.bypass_actors,\n current.rulesetId\n );\n if (bypassDiff) {\n diffs.push(bypassDiff);\n }\n\n return {\n repoInfo,\n branch: current.branch,\n diffs,\n hasChanges: diffs.length > 0,\n currentRulesetId: current.rulesetId,\n };\n}\n\n/** Collect all diffs between current and desired settings */\nfunction collectDiffs(\n current: BranchProtectionSettings,\n desired: DesiredBranchProtection\n): SettingDiff[] {\n const diffs: SettingDiff[] = [];\n\n for (const mapping of fieldMappings) {\n const desiredValue = mapping.getDesiredValue(desired);\n if (desiredValue === undefined) {\n continue;\n }\n\n const currentValue = mapping.getCurrentValue(current);\n const diff = mapping.isArray\n ? compareArrayValue(mapping.name, currentValue as string[] | null, desiredValue as string[])\n : compareValue(mapping.name, currentValue, desiredValue);\n\n if (diff) {\n diffs.push(diff);\n }\n }\n\n return diffs;\n}\n\n/** Compare a single value and return diff if different */\nfunction compareValue(setting: string, current: unknown, desired: unknown): SettingDiff | null {\n const currentValue = current ?? null;\n if (currentValue === desired) {\n return null;\n }\n\n return {\n setting,\n current: currentValue,\n desired,\n action: currentValue === null ? \"add\" : \"change\",\n };\n}\n\n/** Compare arrays and return diff if different */\nfunction compareArrayValue(\n setting: string,\n current: string[] | null,\n desired: string[]\n): SettingDiff | null {\n const currentArray = current ?? [];\n const sortedCurrent = [...currentArray].sort();\n const sortedDesired = [...desired].sort();\n\n const areEqual =\n sortedCurrent.length === sortedDesired.length &&\n sortedCurrent.every((v, i) => v === sortedDesired[i]);\n\n if (areEqual) {\n return null;\n }\n\n return {\n setting,\n current: currentArray,\n desired,\n action: currentArray.length === 0 ? \"add\" : \"change\",\n };\n}\n\n/** Compare bypass actors arrays */\nfunction compareBypassActors(\n current: BypassActor[] | null,\n desired: BypassActor[] | undefined,\n rulesetId: number | null\n): SettingDiff | null {\n if (desired === undefined) {\n return null;\n }\n\n const currentActors = current ?? [];\n\n // Normalize and sort for comparison\n const sortKey = (a: BypassActor): string =>\n `${a.actor_type}:${a.actor_id ?? \"\"}:${a.bypass_mode ?? \"always\"}`;\n\n const sortedCurrent = [...currentActors].sort((a, b) => sortKey(a).localeCompare(sortKey(b)));\n const sortedDesired = [...desired].sort((a, b) => sortKey(a).localeCompare(sortKey(b)));\n\n // Normalize bypass_mode defaults for comparison\n const normalize = (actors: BypassActor[]): BypassActor[] =>\n actors.map((a) => ({\n actor_type: a.actor_type,\n actor_id: a.actor_id,\n bypass_mode: a.bypass_mode ?? \"always\",\n }));\n\n const normalizedCurrent = normalize(sortedCurrent);\n const normalizedDesired = normalize(sortedDesired);\n\n const areEqual =\n normalizedCurrent.length === normalizedDesired.length &&\n normalizedCurrent.every(\n (c, i) =>\n c.actor_type === normalizedDesired[i].actor_type &&\n c.actor_id === normalizedDesired[i].actor_id &&\n c.bypass_mode === normalizedDesired[i].bypass_mode\n );\n\n if (areEqual) {\n return null;\n }\n\n return {\n setting: \"bypass_actors\",\n current: currentActors,\n desired,\n action: rulesetId === null ? \"add\" : \"change\",\n };\n}\n\n/** Format a value for display */\nexport function formatValue(value: unknown): string {\n if (value === null || value === undefined) {\n return \"not set\";\n }\n if (Array.isArray(value)) {\n return value.length === 0 ? \"[]\" : `[${value.join(\", \")}]`;\n }\n return String(value);\n}\n\n// =============================================================================\n// Tag Protection Diff\n// =============================================================================\n\n/** Compare current tag protection with desired and generate diffs */\nexport function computeTagDiff(\n repoInfo: RepoInfo,\n current: TagProtectionSettings,\n desired: DesiredTagProtection\n): TagProtectionDiffResult {\n const diffs: SettingDiff[] = [];\n const rulesetId = current.rulesetId;\n\n collectPatternDiff(diffs, current, desired);\n collectBooleanDiff(diffs, {\n s: \"prevent_deletion\",\n c: current.preventDeletion,\n d: desired.prevent_deletion,\n r: rulesetId,\n });\n collectBooleanDiff(diffs, {\n s: \"prevent_update\",\n c: current.preventUpdate,\n d: desired.prevent_update,\n r: rulesetId,\n });\n\n return { repoInfo, diffs, hasChanges: diffs.length > 0, currentRulesetId: rulesetId };\n}\n\n/** Collect pattern diff if patterns don't match */\nfunction collectPatternDiff(\n diffs: SettingDiff[],\n current: TagProtectionSettings,\n desired: DesiredTagProtection\n): void {\n if (desired.patterns === undefined) {\n return;\n }\n const curr = [...current.patterns].sort();\n const des = [...desired.patterns].sort();\n const match = curr.length === des.length && curr.every((v, i) => v === des[i]);\n if (!match) {\n diffs.push({\n setting: \"patterns\",\n current: current.patterns,\n desired: desired.patterns,\n action: curr.length === 0 ? \"add\" : \"change\",\n });\n }\n}\n\n/** Collect boolean setting diff (s=setting, c=current, d=desired, r=rulesetId) */\nfunction collectBooleanDiff(\n diffs: SettingDiff[],\n o: { s: string; c: boolean; d: boolean | undefined; r: number | null }\n): void {\n if (o.d !== undefined && o.c !== o.d) {\n diffs.push({\n setting: o.s,\n current: o.c,\n desired: o.d,\n action: o.r === null ? \"add\" : \"change\",\n });\n }\n}\n","import { execa } from \"execa\";\n\nimport {\n type BranchProtectionSettings,\n type BypassActor,\n type GitHubRuleset,\n type GitHubRulesetBypassActor,\n type RepoInfo,\n type TagProtectionSettings,\n} from \"./types.js\";\n\n/** Error thrown when fetcher encounters an issue */\nexport class FetcherError extends Error {\n constructor(\n message: string,\n public readonly code: \"NO_GH\" | \"NO_REPO\" | \"NO_PERMISSION\" | \"API_ERROR\"\n ) {\n super(message);\n this.name = \"FetcherError\";\n }\n}\n\n/** Check if gh CLI is available */\nexport async function isGhAvailable(): Promise<boolean> {\n try {\n await execa(\"gh\", [\"--version\"]);\n return true;\n } catch {\n return false;\n }\n}\n\n/** Get repository info from git remote */\nexport async function getRepoInfo(projectRoot: string): Promise<RepoInfo> {\n try {\n const result = await execa(\"gh\", [\"repo\", \"view\", \"--json\", \"owner,name\"], {\n cwd: projectRoot,\n });\n const data = JSON.parse(result.stdout) as { owner: { login: string }; name: string };\n return { owner: data.owner.login, repo: data.name };\n } catch {\n throw new FetcherError(\"Could not determine GitHub repository from git remote\", \"NO_REPO\");\n }\n}\n\n/** Fetch current branch protection settings from GitHub Rulesets */\nexport async function fetchBranchProtection(\n repoInfo: RepoInfo,\n branch: string\n): Promise<BranchProtectionSettings> {\n try {\n const result = await execa(\"gh\", [\"api\", `repos/${repoInfo.owner}/${repoInfo.repo}/rulesets`]);\n\n const rulesets = JSON.parse(result.stdout) as GitHubRuleset[];\n return parseBranchRuleset(rulesets, branch);\n } catch (error) {\n return handleBranchFetchError(error, branch);\n }\n}\n\n/** Handle errors from fetching branch protection */\nfunction handleBranchFetchError(error: unknown, branch: string): BranchProtectionSettings {\n const errorMessage = error instanceof Error ? error.message : String(error);\n\n // 404 means no rulesets exist - return empty settings\n if (errorMessage.includes(\"404\")) {\n return createEmptySettings(branch);\n }\n\n if (errorMessage.includes(\"403\") || errorMessage.includes(\"Must have admin rights\")) {\n throw new FetcherError(\n \"Cannot read branch protection: insufficient permissions (requires admin access)\",\n \"NO_PERMISSION\"\n );\n }\n\n throw new FetcherError(`Failed to fetch branch protection: ${errorMessage}`, \"API_ERROR\");\n}\n\n/** Find and parse the branch protection ruleset */\n// eslint-disable-next-line complexity\nfunction parseBranchRuleset(rulesets: GitHubRuleset[], branch: string): BranchProtectionSettings {\n // Find ruleset targeting branches that includes the specified branch\n const branchRuleset = rulesets.find(\n (r) =>\n r.target === \"branch\" &&\n r.enforcement === \"active\" &&\n matchesBranch(r.conditions?.ref_name?.include ?? [], branch)\n );\n\n if (!branchRuleset) {\n return createEmptySettings(branch);\n }\n\n const rules = branchRuleset.rules ?? [];\n const prRule = rules.find((r) => r.type === \"pull_request\");\n const statusRule = rules.find((r) => r.type === \"required_status_checks\");\n const signaturesRule = rules.find((r) => r.type === \"required_signatures\");\n\n // Parse bypass actors\n const bypassActors = parseBypassActors(branchRuleset.bypass_actors);\n\n // enforceAdmins is true when there are no bypass actors\n const enforceAdmins = bypassActors === null || bypassActors.length === 0;\n\n return {\n branch,\n requiredReviews: prRule?.parameters?.required_approving_review_count ?? null,\n dismissStaleReviews: prRule?.parameters?.dismiss_stale_reviews_on_push ?? null,\n requireCodeOwnerReviews: prRule?.parameters?.require_code_owner_review ?? null,\n requiredStatusChecks:\n statusRule?.parameters?.required_status_checks?.map((c) => c.context) ?? null,\n requireBranchesUpToDate: statusRule?.parameters?.strict_required_status_checks_policy ?? null,\n requireSignedCommits: signaturesRule !== undefined,\n enforceAdmins,\n bypassActors,\n rulesetId: branchRuleset.id,\n rulesetName: branchRuleset.name,\n };\n}\n\n/** Check if branch matches any of the include patterns */\nfunction matchesBranch(patterns: string[], branch: string): boolean {\n for (const pattern of patterns) {\n const cleanPattern = pattern.replace(/^refs\\/heads\\//, \"\");\n if (cleanPattern === branch) {\n return true;\n }\n if (cleanPattern === \"~DEFAULT_BRANCH\" && branch === \"main\") {\n return true;\n }\n if (cleanPattern === \"~ALL\") {\n return true;\n }\n // Simple wildcard matching for patterns like \"release/*\"\n if (cleanPattern.includes(\"*\")) {\n const regex = new RegExp(`^${cleanPattern.replace(/\\*/g, \".*\")}$`);\n if (regex.test(branch)) {\n return true;\n }\n }\n }\n return false;\n}\n\n/** Parse bypass actors from GitHub API response */\nfunction parseBypassActors(actors: GitHubRulesetBypassActor[] | undefined): BypassActor[] | null {\n if (!actors || actors.length === 0) {\n return null;\n }\n\n return actors.map((actor) => ({\n actor_type: actor.actor_type,\n actor_id: actor.actor_id ?? undefined,\n bypass_mode: actor.bypass_mode,\n }));\n}\n\n/** Create empty settings for unprotected branch */\nfunction createEmptySettings(branch: string): BranchProtectionSettings {\n return {\n branch,\n requiredReviews: null,\n dismissStaleReviews: null,\n requireCodeOwnerReviews: null,\n requiredStatusChecks: null,\n requireBranchesUpToDate: null,\n requireSignedCommits: null,\n enforceAdmins: null,\n bypassActors: null,\n rulesetId: null,\n rulesetName: null,\n };\n}\n\n// =============================================================================\n// Tag Protection (GitHub Rulesets API)\n// =============================================================================\n\n/** Fetch current tag protection rulesets from GitHub */\nexport async function fetchTagProtection(repoInfo: RepoInfo): Promise<TagProtectionSettings> {\n try {\n const result = await execa(\"gh\", [\"api\", `repos/${repoInfo.owner}/${repoInfo.repo}/rulesets`]);\n\n const rulesets = JSON.parse(result.stdout) as GitHubRuleset[];\n return parseTagRuleset(rulesets);\n } catch (error) {\n return handleTagFetchError(error);\n }\n}\n\n/** Find and parse the tag protection ruleset */\nfunction parseTagRuleset(rulesets: GitHubRuleset[]): TagProtectionSettings {\n // Find existing tag protection ruleset (by target type and name)\n const tagRuleset = rulesets.find((r) => r.target === \"tag\" && r.name === \"Tag Protection\");\n\n if (!tagRuleset) {\n return createEmptyTagSettings();\n }\n\n const patterns =\n tagRuleset.conditions?.ref_name?.include?.map((p) => p.replace(/^refs\\/tags\\//, \"\")) ?? [];\n\n const rules = tagRuleset.rules ?? [];\n const preventDeletion = rules.some((r) => r.type === \"deletion\");\n const preventUpdate = rules.some((r) => r.type === \"update\");\n\n return {\n patterns,\n preventDeletion,\n preventUpdate,\n rulesetId: tagRuleset.id,\n rulesetName: tagRuleset.name,\n };\n}\n\n/** Create empty settings when no tag ruleset exists */\nfunction createEmptyTagSettings(): TagProtectionSettings {\n return {\n patterns: [],\n preventDeletion: false,\n preventUpdate: false,\n rulesetId: null,\n rulesetName: null,\n };\n}\n\n/** Handle errors from fetching tag protection */\nfunction handleTagFetchError(error: unknown): TagProtectionSettings {\n const errorMessage = error instanceof Error ? error.message : String(error);\n\n // 404 means no rulesets exist - return empty settings\n if (errorMessage.includes(\"404\")) {\n return createEmptyTagSettings();\n }\n\n if (errorMessage.includes(\"403\") || errorMessage.includes(\"Must have admin rights\")) {\n throw new FetcherError(\n \"Cannot read tag protection: insufficient permissions (requires admin access)\",\n \"NO_PERMISSION\"\n );\n }\n\n throw new FetcherError(`Failed to fetch tag protection: ${errorMessage}`, \"API_ERROR\");\n}\n","import { getProjectRoot, loadConfig } from \"../../core/index.js\";\nimport { ApplierError, applyBranchProtection, applyTagProtection } from \"./applier.js\";\nimport { computeDiff, computeTagDiff, formatValue } from \"./differ.js\";\nimport {\n fetchBranchProtection,\n FetcherError,\n fetchTagProtection,\n getRepoInfo,\n isGhAvailable,\n} from \"./fetcher.js\";\nimport {\n type SyncDiffResult,\n type SyncOptions,\n type SyncResult,\n type TagProtectionDiffResult,\n} from \"./types.js\";\n\n/** Helper to write to stdout */\nfunction writeLine(text: string): void {\n process.stdout.write(`${text}\\n`);\n}\n\n/** Run diff command - show what would change */\nexport async function runDiff(options: SyncOptions): Promise<void> {\n try {\n const diffResult = await getDiffResult(options);\n outputDiff(diffResult, options.format);\n process.exit(diffResult.hasChanges ? 1 : 0);\n } catch (error) {\n handleError(error, options.format);\n }\n}\n\n/** Run sync command - apply changes (or preview if --apply not set) */\n// eslint-disable-next-line max-statements\nexport async function runSync(options: SyncOptions): Promise<void> {\n try {\n const diffResult = await getDiffResult(options);\n\n if (!diffResult.hasChanges) {\n outputNoChanges(diffResult, options.format);\n process.exit(0);\n }\n\n // Validate actors if requested\n if (options.validateActors) {\n const validationPassed = await validateActorsBeforeApply(options);\n if (!validationPassed) {\n process.exit(1);\n }\n }\n\n if (!options.apply) {\n outputPreview(diffResult, options.format);\n process.exit(0);\n }\n\n const result = await applyChanges(options, diffResult);\n outputSyncResult(diffResult, result, options.format);\n process.exit(result.success ? 0 : 1);\n } catch (error) {\n handleError(error, options.format);\n }\n}\n\n/** Apply changes to GitHub */\nasync function applyChanges(options: SyncOptions, diffResult: SyncDiffResult): Promise<SyncResult> {\n const { config } = loadConfig(options.config);\n const projectRoot = getProjectRoot(loadConfig(options.config).configPath);\n const repoInfo = await getRepoInfo(projectRoot);\n const desired = config.process?.repo?.ruleset ?? {};\n\n return applyBranchProtection(repoInfo, diffResult.branch, desired, diffResult);\n}\n\n/** Validate bypass actors before applying changes */\nasync function validateActorsBeforeApply(options: SyncOptions): Promise<boolean> {\n const { validateBypassActors, formatValidationResult } = await import(\"./validator.js\");\n const { config } = loadConfig(options.config);\n const projectRoot = getProjectRoot(loadConfig(options.config).configPath);\n const repoInfo = await getRepoInfo(projectRoot);\n\n const rulesetConfig = config.process?.repo?.ruleset;\n const actors = rulesetConfig?.bypass_actors ?? [];\n\n if (actors.length === 0) {\n return true;\n }\n\n const result = await validateBypassActors(repoInfo, actors);\n\n if (options.format === \"json\") {\n process.stdout.write(`${JSON.stringify(result, null, 2)}\\n`);\n } else {\n process.stdout.write(`${formatValidationResult(result)}\\n`);\n }\n\n return result.valid;\n}\n\n/** Get the diff result (shared by diff and sync) */\nasync function getDiffResult(options: SyncOptions): Promise<SyncDiffResult> {\n if (!(await isGhAvailable())) {\n throw new FetcherError(\"GitHub CLI (gh) not available\", \"NO_GH\");\n }\n\n const { config, configPath } = loadConfig(options.config);\n const projectRoot = getProjectRoot(configPath);\n const repoInfo = await getRepoInfo(projectRoot);\n\n const repoConfig = config.process?.repo;\n const desired = repoConfig?.ruleset;\n if (!desired) {\n throw new Error(\"No [process.repo.ruleset] configured in standards.toml\");\n }\n const branch = getBranch(desired.branch);\n const current = await fetchBranchProtection(repoInfo, branch);\n\n return computeDiff(repoInfo, current, desired);\n}\n\n/** Get branch name with default */\nfunction getBranch(configuredBranch: string | undefined): string {\n return configuredBranch ?? \"main\";\n}\n\n/** Output diff result */\nfunction outputDiff(result: SyncDiffResult, format: \"text\" | \"json\"): void {\n if (format === \"json\") {\n writeLine(JSON.stringify(result, null, 2));\n } else {\n outputDiffText(result);\n }\n}\n\n/** Output diff in text format */\nfunction outputDiffText(result: SyncDiffResult): void {\n writeRepoHeader(result);\n\n if (!result.hasChanges) {\n writeLine(\"No changes needed. Settings match configuration.\");\n return;\n }\n\n writeDiffTable(result);\n writeLine(\"\");\n writeLine(\n `${result.diffs.length} setting(s) differ. Run 'conform process sync --apply' to apply changes.`\n );\n}\n\n/** Write repository header */\nfunction writeRepoHeader(result: SyncDiffResult): void {\n writeLine(`Repository: ${result.repoInfo.owner}/${result.repoInfo.repo}`);\n writeLine(`Branch: ${result.branch}`);\n writeLine(\"\");\n}\n\n/** Write diff table */\nfunction writeDiffTable(result: SyncDiffResult): void {\n const settingWidth = Math.max(...result.diffs.map((d) => d.setting.length), 7);\n const currentWidth = Math.max(...result.diffs.map((d) => formatValue(d.current).length), 7);\n\n writeLine(`${\"Setting\".padEnd(settingWidth)} ${\"Current\".padEnd(currentWidth)} Desired`);\n writeLine(\"-\".repeat(settingWidth + currentWidth + 20));\n\n for (const diff of result.diffs) {\n const currentStr = formatValue(diff.current);\n const desiredStr = formatValue(diff.desired);\n writeLine(\n `${diff.setting.padEnd(settingWidth)} ${currentStr.padEnd(currentWidth)} ${desiredStr}`\n );\n }\n}\n\n/** Output when no changes are needed */\nfunction outputNoChanges(result: SyncDiffResult, format: \"text\" | \"json\"): void {\n if (format === \"json\") {\n writeLine(JSON.stringify({ ...result, message: \"No changes needed\" }, null, 2));\n } else {\n writeRepoHeader(result);\n writeLine(\"No changes needed. Settings match configuration.\");\n }\n}\n\n/** Output preview (sync without --apply) */\nfunction outputPreview(result: SyncDiffResult, format: \"text\" | \"json\"): void {\n if (format === \"json\") {\n writeLine(JSON.stringify({ ...result, preview: true }, null, 2));\n } else {\n writeRepoHeader(result);\n writeLine(\"Would apply the following changes:\");\n for (const diff of result.diffs) {\n writeLine(` ${diff.setting}: ${formatValue(diff.current)} -> ${formatValue(diff.desired)}`);\n }\n writeLine(\"\");\n writeLine(\"Run with --apply to make these changes.\");\n }\n}\n\n/** Output sync result */\nfunction outputSyncResult(\n diffResult: SyncDiffResult,\n result: SyncResult,\n format: \"text\" | \"json\"\n): void {\n if (format === \"json\") {\n writeLine(\n JSON.stringify(\n { repoInfo: diffResult.repoInfo, branch: diffResult.branch, ...result },\n null,\n 2\n )\n );\n } else {\n outputSyncResultText(diffResult, result);\n }\n}\n\n/** Output sync result in text format */\nfunction outputSyncResultText(diffResult: SyncDiffResult, result: SyncResult): void {\n writeRepoHeader(diffResult);\n writeLine(\"Applying changes...\");\n\n for (const diff of result.applied) {\n writeLine(` + ${diff.setting}: ${formatValue(diff.current)} -> ${formatValue(diff.desired)}`);\n }\n\n for (const { diff, error } of result.failed) {\n writeLine(` x ${diff.setting}: ${error}`);\n }\n\n writeLine(\"\");\n if (result.success) {\n writeLine(`+ ${result.applied.length} setting(s) synchronized successfully.`);\n } else {\n writeLine(`x ${result.failed.length} setting(s) failed to sync.`);\n }\n}\n\n/** Handle errors */\nfunction handleError(error: unknown, format: \"text\" | \"json\"): void {\n const { message, code } = extractErrorInfo(error);\n\n if (format === \"json\") {\n writeLine(JSON.stringify({ error: true, code, message }, null, 2));\n } else {\n writeLine(`Error: ${message}`);\n }\n\n process.exit(2);\n}\n\n/** Extract error message and code */\nfunction extractErrorInfo(error: unknown): { message: string; code: string } {\n if (error instanceof FetcherError) {\n return { message: error.message, code: error.code };\n }\n if (error instanceof ApplierError) {\n return { message: error.message, code: error.code };\n }\n if (error instanceof Error) {\n return { message: error.message, code: \"ERROR\" };\n }\n return { message: String(error), code: \"ERROR\" };\n}\n\n// =============================================================================\n// Tag Protection Sync\n// =============================================================================\n\n/** Run tag protection diff command - show what would change */\nexport async function runTagDiff(options: SyncOptions): Promise<void> {\n try {\n const diffResult = await getTagDiffResult(options);\n outputTagDiff(diffResult, options.format);\n process.exit(diffResult.hasChanges ? 1 : 0);\n } catch (error) {\n handleError(error, options.format);\n }\n}\n\n/** Run tag protection sync command - apply changes (or preview if --apply not set) */\nexport async function runTagSync(options: SyncOptions): Promise<void> {\n try {\n const diffResult = await getTagDiffResult(options);\n\n if (!diffResult.hasChanges) {\n outputTagNoChanges(diffResult, options.format);\n process.exit(0);\n }\n\n if (!options.apply) {\n outputTagPreview(diffResult, options.format);\n process.exit(0);\n }\n\n const result = await applyTagChanges(options, diffResult);\n outputTagSyncResult(diffResult, result, options.format);\n process.exit(result.success ? 0 : 1);\n } catch (error) {\n handleError(error, options.format);\n }\n}\n\n/** Get the tag diff result */\nasync function getTagDiffResult(options: SyncOptions): Promise<TagProtectionDiffResult> {\n if (!(await isGhAvailable())) {\n throw new FetcherError(\"GitHub CLI (gh) not available\", \"NO_GH\");\n }\n\n const { config, configPath } = loadConfig(options.config);\n const projectRoot = getProjectRoot(configPath);\n const repoInfo = await getRepoInfo(projectRoot);\n\n const repoConfig = config.process?.repo;\n if (!repoConfig?.tag_protection?.patterns || repoConfig.tag_protection.patterns.length === 0) {\n throw new Error(\"No [process.repo.tag_protection] patterns configured in standards.toml\");\n }\n\n const desired = repoConfig.tag_protection;\n const current = await fetchTagProtection(repoInfo);\n\n return computeTagDiff(repoInfo, current, desired);\n}\n\n/** Apply tag protection changes to GitHub */\nasync function applyTagChanges(\n options: SyncOptions,\n diffResult: TagProtectionDiffResult\n): Promise<SyncResult> {\n const { config } = loadConfig(options.config);\n const desired = config.process?.repo?.tag_protection ?? {};\n\n return applyTagProtection(diffResult.repoInfo, desired, diffResult);\n}\n\n/** Output tag diff result */\nfunction outputTagDiff(result: TagProtectionDiffResult, format: \"text\" | \"json\"): void {\n if (format === \"json\") {\n writeLine(JSON.stringify(result, null, 2));\n } else {\n outputTagDiffText(result);\n }\n}\n\n/** Output tag diff in text format */\nfunction outputTagDiffText(result: TagProtectionDiffResult): void {\n writeTagRepoHeader(result);\n\n if (!result.hasChanges) {\n writeLine(\"No changes needed. Tag protection settings match configuration.\");\n return;\n }\n\n writeTagDiffTable(result);\n writeLine(\"\");\n writeLine(\n `${result.diffs.length} setting(s) differ. Run 'conform process sync-tags --apply' to apply changes.`\n );\n}\n\n/** Write tag repository header */\nfunction writeTagRepoHeader(result: TagProtectionDiffResult): void {\n writeLine(`Repository: ${result.repoInfo.owner}/${result.repoInfo.repo}`);\n writeLine(`Target: Tag Protection Ruleset`);\n writeLine(\"\");\n}\n\n/** Write tag diff table */\nfunction writeTagDiffTable(result: TagProtectionDiffResult): void {\n const settingWidth = Math.max(...result.diffs.map((d) => d.setting.length), 7);\n const currentWidth = Math.max(...result.diffs.map((d) => formatValue(d.current).length), 7);\n\n writeLine(`${\"Setting\".padEnd(settingWidth)} ${\"Current\".padEnd(currentWidth)} Desired`);\n writeLine(\"-\".repeat(settingWidth + currentWidth + 20));\n\n for (const diff of result.diffs) {\n const currentStr = formatValue(diff.current);\n const desiredStr = formatValue(diff.desired);\n writeLine(\n `${diff.setting.padEnd(settingWidth)} ${currentStr.padEnd(currentWidth)} ${desiredStr}`\n );\n }\n}\n\n/** Output when no tag changes are needed */\nfunction outputTagNoChanges(result: TagProtectionDiffResult, format: \"text\" | \"json\"): void {\n if (format === \"json\") {\n writeLine(JSON.stringify({ ...result, message: \"No changes needed\" }, null, 2));\n } else {\n writeTagRepoHeader(result);\n writeLine(\"No changes needed. Tag protection settings match configuration.\");\n }\n}\n\n/** Output tag preview (sync without --apply) */\nfunction outputTagPreview(result: TagProtectionDiffResult, format: \"text\" | \"json\"): void {\n if (format === \"json\") {\n writeLine(JSON.stringify({ ...result, preview: true }, null, 2));\n } else {\n writeTagRepoHeader(result);\n writeLine(\"Would apply the following changes:\");\n for (const diff of result.diffs) {\n writeLine(` ${diff.setting}: ${formatValue(diff.current)} -> ${formatValue(diff.desired)}`);\n }\n writeLine(\"\");\n writeLine(\"Run with --apply to make these changes.\");\n }\n}\n\n/** Output tag sync result */\nfunction outputTagSyncResult(\n diffResult: TagProtectionDiffResult,\n result: SyncResult,\n format: \"text\" | \"json\"\n): void {\n if (format === \"json\") {\n writeLine(JSON.stringify({ repoInfo: diffResult.repoInfo, ...result }, null, 2));\n } else {\n outputTagSyncResultText(diffResult, result);\n }\n}\n\n/** Output tag sync result in text format */\nfunction outputTagSyncResultText(diffResult: TagProtectionDiffResult, result: SyncResult): void {\n writeTagRepoHeader(diffResult);\n writeLine(\"Applying tag protection changes...\");\n\n for (const diff of result.applied) {\n writeLine(` + ${diff.setting}: ${formatValue(diff.current)} -> ${formatValue(diff.desired)}`);\n }\n\n for (const { diff, error } of result.failed) {\n writeLine(` x ${diff.setting}: ${error}`);\n }\n\n writeLine(\"\");\n if (result.success) {\n writeLine(`+ ${result.applied.length} setting(s) synchronized successfully.`);\n } else {\n writeLine(`x ${result.failed.length} setting(s) failed to sync.`);\n }\n}\n"],"mappings":"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","names":["execa"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/validate/guidelines.ts","../src/validate/tier.ts","../src/validate/types.ts"],"sourcesContent":["/**\n * Validate guideline markdown files against the frontmatter schema\n */\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\n\nimport chalk from \"chalk\";\nimport matter from \"gray-matter\";\n\nimport { frontmatterSchema } from \"../mcp/standards/index.js\";\nimport { ExitCode } from \"../core/index.js\";\n\n/** Single file validation error */\nexport interface GuidelineValidationError {\n file: string;\n errors: string[];\n}\n\n/** Overall validation result */\nexport interface GuidelineValidationResult {\n valid: boolean;\n validCount: number;\n invalidCount: number;\n errors: GuidelineValidationError[];\n}\n\n/** Format text output for validation result */\nfunction formatTextOutput(result: GuidelineValidationResult): string {\n if (result.valid) {\n return chalk.green(`✓ All ${result.validCount} guideline(s) valid`);\n }\n const lines = [chalk.red(`✗ Found ${result.invalidCount} invalid guideline(s)`), \"\"];\n for (const err of result.errors) {\n lines.push(chalk.red(` ${err.file}:`));\n for (const e of err.errors) {\n lines.push(chalk.red(` - ${e}`));\n }\n }\n return lines.join(\"\\n\");\n}\n\n/** Validate a directory of guideline files */\nexport function validateGuidelinesDir(dirPath: string): GuidelineValidationResult {\n const files = fs.readdirSync(dirPath).filter((f) => f.endsWith(\".md\"));\n const result: GuidelineValidationResult = {\n valid: true,\n validCount: 0,\n invalidCount: 0,\n errors: [],\n };\n\n for (const file of files) {\n const filePath = path.join(dirPath, file);\n const content = fs.readFileSync(filePath, \"utf-8\");\n const { data } = matter(content);\n\n const parseResult = frontmatterSchema.safeParse(data);\n if (parseResult.success) {\n result.validCount++;\n } else {\n result.valid = false;\n result.invalidCount++;\n result.errors.push({\n file,\n errors: parseResult.error.errors.map((e) => `${e.path.join(\".\")}: ${e.message}`),\n });\n }\n }\n\n return result;\n}\n\n/** Output error and exit */\nfunction exitWithError(error: string, format: string): never {\n if (format === \"json\") {\n process.stdout.write(`${JSON.stringify({ valid: false, error }, null, 2)}\\n`);\n } else {\n console.error(chalk.red(`✗ ${error}`));\n }\n process.exit(ExitCode.CONFIG_ERROR);\n}\n\n/** Resolve and validate directory path */\nfunction resolveAndValidatePath(dirPath: string, format: string): string {\n const resolvedPath = path.isAbsolute(dirPath) ? dirPath : path.resolve(process.cwd(), dirPath);\n\n if (!fs.existsSync(resolvedPath)) {\n exitWithError(`Path does not exist: ${resolvedPath}`, format);\n }\n\n const stats = fs.statSync(resolvedPath);\n if (!stats.isDirectory()) {\n exitWithError(`Path is not a directory: ${resolvedPath}`, format);\n }\n\n return resolvedPath;\n}\n\n/** Run the validate guidelines command */\nexport async function runValidateGuidelines(\n dirPath: string,\n options: { format: string }\n): Promise<void> {\n const resolvedPath = resolveAndValidatePath(dirPath, options.format);\n const result = validateGuidelinesDir(resolvedPath);\n\n if (options.format === \"json\") {\n process.stdout.write(`${JSON.stringify(result, null, 2)}\\n`);\n } else {\n process.stdout.write(`${formatTextOutput(result)}\\n`);\n }\n\n process.exit(result.valid ? ExitCode.SUCCESS : ExitCode.CONFIG_ERROR);\n}\n","import { execSync } from \"node:child_process\";\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\n\nimport TOML from \"@iarna/toml\";\nimport chalk from \"chalk\";\nimport * as yaml from \"js-yaml\";\n\nimport { findConfigFile, getProjectRoot } from \"../core/index.js\";\nimport {\n type RepoMetadata,\n type Tier,\n type TierSourceDetail,\n VALID_TIERS,\n type ValidateTierOptions,\n type ValidateTierResult,\n} from \"./types.js\";\n\n/** Default tier when not specified */\nconst DEFAULT_TIER: Tier = \"internal\";\n\n/** Extends section from standards.toml */\ninterface ExtendsConfig {\n registry?: string;\n rulesets?: string[];\n}\n\n/** Raw standards.toml structure (just what we need) */\ninterface RawConfig {\n extends?: ExtendsConfig;\n}\n\n/** Result of loading repo-metadata.yaml with detailed source info */\ninterface LoadMetadataResult {\n metadata: RepoMetadata | null;\n sourceDetail: TierSourceDetail;\n parseError?: string;\n}\n\n/**\n * Find the git repository root directory\n */\nfunction findGitRoot(startDir: string): string | null {\n try {\n const gitRoot = execSync(\"git rev-parse --show-toplevel\", {\n cwd: startDir,\n encoding: \"utf-8\",\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n }).trim();\n return gitRoot;\n } catch {\n return null;\n }\n}\n\n/**\n * Read file content, returns null if file doesn't exist or can't be read\n */\nfunction readFileContent(filePath: string): string | null {\n if (!fs.existsSync(filePath)) {\n return null;\n }\n try {\n return fs.readFileSync(filePath, \"utf-8\");\n } catch {\n return null;\n }\n}\n\n/**\n * Parse YAML content into RepoMetadata\n */\nfunction parseYamlContent(content: string): LoadMetadataResult {\n try {\n const parsed: unknown = yaml.load(content);\n // yaml.load returns undefined for empty content, null for \"null\"\n if (parsed === undefined || parsed === null) {\n return { metadata: null, sourceDetail: \"default (file empty)\" };\n }\n return { metadata: parsed as RepoMetadata, sourceDetail: \"repo-metadata.yaml\" };\n } catch (error) {\n const parseError = error instanceof Error ? error.message : String(error);\n return { metadata: null, sourceDetail: \"default (parse error)\", parseError };\n }\n}\n\n/**\n * Load and parse repo-metadata.yaml with detailed error tracking\n */\nfunction loadRepoMetadata(projectRoot: string): LoadMetadataResult {\n const metadataPath = path.join(projectRoot, \"repo-metadata.yaml\");\n const content = readFileContent(metadataPath);\n\n if (content === null) {\n return { metadata: null, sourceDetail: \"default (file not found)\" };\n }\n if (!content.trim()) {\n return { metadata: null, sourceDetail: \"default (file empty)\" };\n }\n\n return parseYamlContent(content);\n}\n\n/**\n * Load and parse standards.toml to get extends section\n */\nfunction loadExtendsConfig(configPath: string): ExtendsConfig | null {\n try {\n const content = fs.readFileSync(configPath, \"utf-8\");\n const parsed = TOML.parse(content) as RawConfig;\n return parsed.extends ?? null;\n } catch {\n return null;\n }\n}\n\n/** Result of getTier with detailed info */\ninterface GetTierResult {\n tier: Tier;\n source: \"repo-metadata.yaml\" | \"default\";\n sourceDetail: TierSourceDetail;\n invalidValue?: string;\n}\n\n/**\n * Get tier from repo-metadata.yaml with validation\n */\nfunction getTier(metadataResult: LoadMetadataResult): GetTierResult {\n const { metadata, sourceDetail } = metadataResult;\n\n // If metadata loading failed, return with the detailed reason\n if (!metadata) {\n return { tier: DEFAULT_TIER, source: \"default\", sourceDetail };\n }\n\n // Metadata exists but tier key is missing\n if (metadata.tier === undefined) {\n return { tier: DEFAULT_TIER, source: \"default\", sourceDetail: \"default (tier not specified)\" };\n }\n\n const tier = metadata.tier;\n\n // Check if tier value is valid\n if (!VALID_TIERS.includes(tier)) {\n return {\n tier: DEFAULT_TIER,\n source: \"default\",\n sourceDetail: \"default (invalid value)\",\n invalidValue: String(tier),\n };\n }\n\n return { tier, source: \"repo-metadata.yaml\", sourceDetail: \"repo-metadata.yaml\" };\n}\n\n/**\n * Check if rulesets include a tier-matching ruleset\n */\nfunction findMatchingRulesets(rulesets: string[], tier: Tier): string[] {\n const suffix = `-${tier}`;\n return rulesets.filter((ruleset) => ruleset.endsWith(suffix));\n}\n\n/**\n * Resolve the config path from options\n */\nfunction resolveConfigPath(options: ValidateTierOptions): string | null {\n if (options.config) {\n const absolutePath = path.resolve(options.config);\n return fs.existsSync(absolutePath) ? absolutePath : null;\n }\n return findConfigFile();\n}\n\n/**\n * Create result for missing config\n */\nfunction createNotFoundResult(): ValidateTierResult {\n return {\n valid: false,\n tier: DEFAULT_TIER,\n tierSource: \"default\",\n rulesets: [],\n expectedPattern: `*-${DEFAULT_TIER}`,\n matchedRulesets: [],\n error: \"No standards.toml found\",\n };\n}\n\n/** Options for building the result */\ninterface BuildResultOptions {\n tier: Tier;\n source: \"repo-metadata.yaml\" | \"default\";\n sourceDetail: TierSourceDetail;\n rulesets: string[];\n matchedRulesets: string[];\n invalidTierValue?: string;\n hasEmptyRulesets?: boolean;\n registryUrl?: string;\n warnings?: string[];\n parseError?: string;\n}\n\n/**\n * Build the validation result\n */\nfunction buildResult(options: BuildResultOptions): ValidateTierResult {\n const {\n tier,\n source,\n sourceDetail,\n rulesets,\n matchedRulesets,\n invalidTierValue,\n hasEmptyRulesets,\n registryUrl,\n parseError,\n } = options;\n const warnings: string[] = options.warnings ?? [];\n\n const expectedPattern = `*-${tier}`;\n const valid = rulesets.length === 0 || matchedRulesets.length > 0;\n\n // Add warning for invalid tier value\n if (invalidTierValue) {\n warnings.push(\n `Invalid tier '${invalidTierValue}' in repo-metadata.yaml. Valid values are: ${VALID_TIERS.join(\", \")}`\n );\n }\n\n // Add warning for parse error\n if (parseError) {\n warnings.push(`Failed to parse repo-metadata.yaml: ${parseError}`);\n }\n\n // Add warning for empty rulesets with registry configured\n if (hasEmptyRulesets && registryUrl) {\n warnings.push(\n `[extends] is configured with registry '${registryUrl}' but rulesets is empty - no standards will be inherited`\n );\n }\n\n return {\n valid,\n tier,\n tierSource: source,\n tierSourceDetail: sourceDetail,\n rulesets,\n expectedPattern,\n matchedRulesets,\n error: valid\n ? undefined\n : `No ruleset matching pattern '${expectedPattern}' found. Rulesets: [${rulesets.join(\", \")}]`,\n invalidTierValue,\n hasEmptyRulesets,\n registryUrl,\n warnings: warnings.length > 0 ? warnings : undefined,\n };\n}\n\n/**\n * Validate that project tier matches its rulesets.\n * This is the programmatic API exported for library consumers.\n */\nexport function validateTierRuleset(options: ValidateTierOptions = {}): ValidateTierResult {\n const configPath = resolveConfigPath(options);\n if (!configPath) {\n return createNotFoundResult();\n }\n\n // Try to find repo-metadata.yaml from git root first, fall back to config directory\n const configDir = getProjectRoot(configPath);\n const gitRoot = findGitRoot(configDir);\n const metadataSearchPath = gitRoot ?? configDir;\n\n const metadataResult = loadRepoMetadata(metadataSearchPath);\n const { tier, source, sourceDetail, invalidValue } = getTier(metadataResult);\n\n const extendsConfig = loadExtendsConfig(configPath);\n const rulesets = extendsConfig?.rulesets ?? [];\n const matchedRulesets = rulesets.length > 0 ? findMatchingRulesets(rulesets, tier) : [];\n\n // Detect empty rulesets with registry configured\n const hasEmptyRulesets = extendsConfig !== null && rulesets.length === 0;\n const registryUrl = extendsConfig?.registry;\n\n return buildResult({\n tier,\n source,\n sourceDetail,\n rulesets,\n matchedRulesets,\n invalidTierValue: invalidValue,\n hasEmptyRulesets,\n registryUrl,\n parseError: metadataResult.parseError,\n });\n}\n\n/** Format warnings section */\nfunction formatWarnings(warnings: string[] | undefined): string[] {\n if (!warnings || warnings.length === 0) {\n return [];\n }\n const lines = warnings.map((w) => chalk.yellow(`⚠ Warning: ${w}`));\n lines.push(\"\"); // Empty line after warnings\n return lines;\n}\n\n/** Format the rulesets message based on configuration */\nfunction formatRulesetsMessage(result: ValidateTierResult): string {\n if (result.matchedRulesets.length > 0) {\n return ` Matching rulesets: ${result.matchedRulesets.join(\", \")}`;\n }\n if (result.hasEmptyRulesets) {\n return \" No rulesets specified (no tier constraint)\";\n }\n return \" No extends configured (no tier constraint)\";\n}\n\n/** Format the failed validation section */\nfunction formatFailedValidation(result: ValidateTierResult, sourceDisplay: string): string[] {\n const lines = [\n chalk.red(\"✗ Tier validation failed\"),\n ` Tier: ${result.tier} (source: ${sourceDisplay})`,\n ` Expected pattern: ${result.expectedPattern}`,\n ` Rulesets: [${result.rulesets.join(\", \")}]`,\n ];\n if (result.error) {\n lines.push(chalk.red(` Error: ${result.error}`));\n }\n if (result.invalidTierValue) {\n lines.push(\"\");\n lines.push(\n chalk.cyan(\n ` Hint: Update repo-metadata.yaml to use a valid tier value: ${VALID_TIERS.join(\", \")}`\n )\n );\n }\n return lines;\n}\n\n/**\n * Format tier validation result as text\n */\nexport function formatTierResultText(result: ValidateTierResult): string {\n const lines: string[] = formatWarnings(result.warnings);\n const sourceDisplay = result.tierSourceDetail ?? result.tierSource;\n\n if (result.valid) {\n lines.push(chalk.green(\"✓ Tier validation passed\"));\n lines.push(` Tier: ${result.tier} (source: ${sourceDisplay})`);\n lines.push(formatRulesetsMessage(result));\n } else {\n lines.push(...formatFailedValidation(result, sourceDisplay));\n }\n\n return lines.join(\"\\n\");\n}\n\n/**\n * Format tier validation result as JSON\n */\nexport function formatTierResultJson(result: ValidateTierResult): string {\n return JSON.stringify(result, null, 2);\n}\n","/**\n * Valid project tiers\n */\nexport type Tier = \"production\" | \"internal\" | \"prototype\";\n\n/**\n * Valid tier values as a constant array for validation and export\n */\nexport const VALID_TIERS: readonly Tier[] = [\"production\", \"internal\", \"prototype\"];\n\n/**\n * Parsed repo-metadata.yaml structure\n */\nexport interface RepoMetadata {\n tier?: Tier;\n}\n\n/**\n * Detailed tier source indicating why a default was used\n */\nexport type TierSourceDetail =\n | \"repo-metadata.yaml\" // Tier was read from file\n | \"default\" // Generic default (for backwards compatibility)\n | \"default (file not found)\" // File doesn't exist\n | \"default (file empty)\" // File exists but is empty\n | \"default (parse error)\" // File exists but YAML is invalid\n | \"default (tier not specified)\" // File valid but no tier key\n | \"default (invalid value)\"; // File has tier but value is invalid\n\n/**\n * Options for the tier validation command\n */\nexport interface ValidateTierOptions {\n /** Path to standards.toml config file */\n config?: string;\n /** Output format */\n format?: \"text\" | \"json\";\n}\n\n/**\n * Result of tier validation\n */\nexport interface ValidateTierResult {\n /** Whether validation passed */\n valid: boolean;\n /** Project tier from repo-metadata.yaml (defaults to \"internal\") */\n tier: Tier;\n /** Source of tier value */\n tierSource: \"repo-metadata.yaml\" | \"default\";\n /** Detailed source of tier value with reason for default */\n tierSourceDetail?: TierSourceDetail;\n /** Rulesets from standards.toml extends section */\n rulesets: string[];\n /** Expected ruleset suffix pattern */\n expectedPattern: string;\n /** Matched rulesets (those that satisfy the tier requirement) */\n matchedRulesets: string[];\n /** Error message if invalid */\n error?: string;\n /** Invalid tier value that was rejected (for error messages) */\n invalidTierValue?: string;\n /** Whether extends is configured but has empty rulesets */\n hasEmptyRulesets?: boolean;\n /** Registry URL if extends is configured */\n registryUrl?: string;\n /** Warnings about configuration */\n warnings?: string[];\n}\n"],"mappings":"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","names":["fs","path","chalk","chalk"]}