@vertaaux/cli 0.2.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 (198) hide show
  1. package/README.md +345 -0
  2. package/dist/auth/ci-token.d.ts +49 -0
  3. package/dist/auth/ci-token.d.ts.map +1 -0
  4. package/dist/auth/ci-token.js +83 -0
  5. package/dist/auth/device-flow.d.ts +66 -0
  6. package/dist/auth/device-flow.d.ts.map +1 -0
  7. package/dist/auth/device-flow.js +156 -0
  8. package/dist/auth/token-store.d.ts +53 -0
  9. package/dist/auth/token-store.d.ts.map +1 -0
  10. package/dist/auth/token-store.js +78 -0
  11. package/dist/baseline/diff.d.ts +57 -0
  12. package/dist/baseline/diff.d.ts.map +1 -0
  13. package/dist/baseline/diff.js +152 -0
  14. package/dist/baseline/hash.d.ts +54 -0
  15. package/dist/baseline/hash.d.ts.map +1 -0
  16. package/dist/baseline/hash.js +66 -0
  17. package/dist/baseline/manager.d.ts +89 -0
  18. package/dist/baseline/manager.d.ts.map +1 -0
  19. package/dist/baseline/manager.js +157 -0
  20. package/dist/cache/index.d.ts +8 -0
  21. package/dist/cache/index.d.ts.map +1 -0
  22. package/dist/cache/index.js +7 -0
  23. package/dist/cache/route-cache.d.ts +119 -0
  24. package/dist/cache/route-cache.d.ts.map +1 -0
  25. package/dist/cache/route-cache.js +213 -0
  26. package/dist/ci/changed-routes.d.ts +95 -0
  27. package/dist/ci/changed-routes.d.ts.map +1 -0
  28. package/dist/ci/changed-routes.js +304 -0
  29. package/dist/ci/github-api.d.ts +68 -0
  30. package/dist/ci/github-api.d.ts.map +1 -0
  31. package/dist/ci/github-api.js +138 -0
  32. package/dist/ci/gitlab-api.d.ts +75 -0
  33. package/dist/ci/gitlab-api.d.ts.map +1 -0
  34. package/dist/ci/gitlab-api.js +180 -0
  35. package/dist/ci/index.d.ts +6 -0
  36. package/dist/ci/index.d.ts.map +1 -0
  37. package/dist/ci/index.js +4 -0
  38. package/dist/commands/audit.d.ts +58 -0
  39. package/dist/commands/audit.d.ts.map +1 -0
  40. package/dist/commands/audit.js +862 -0
  41. package/dist/commands/baseline.d.ts +22 -0
  42. package/dist/commands/baseline.d.ts.map +1 -0
  43. package/dist/commands/baseline.js +210 -0
  44. package/dist/commands/comment.d.ts +14 -0
  45. package/dist/commands/comment.d.ts.map +1 -0
  46. package/dist/commands/comment.js +363 -0
  47. package/dist/commands/diff.d.ts +24 -0
  48. package/dist/commands/diff.d.ts.map +1 -0
  49. package/dist/commands/diff.js +196 -0
  50. package/dist/commands/doctor.d.ts +58 -0
  51. package/dist/commands/doctor.d.ts.map +1 -0
  52. package/dist/commands/doctor.js +338 -0
  53. package/dist/commands/download.d.ts +12 -0
  54. package/dist/commands/download.d.ts.map +1 -0
  55. package/dist/commands/download.js +183 -0
  56. package/dist/commands/explain.d.ts +62 -0
  57. package/dist/commands/explain.d.ts.map +1 -0
  58. package/dist/commands/explain.js +302 -0
  59. package/dist/commands/init.d.ts +12 -0
  60. package/dist/commands/init.d.ts.map +1 -0
  61. package/dist/commands/init.js +212 -0
  62. package/dist/commands/login.d.ts +14 -0
  63. package/dist/commands/login.d.ts.map +1 -0
  64. package/dist/commands/login.js +222 -0
  65. package/dist/commands/policy.d.ts +13 -0
  66. package/dist/commands/policy.d.ts.map +1 -0
  67. package/dist/commands/policy.js +347 -0
  68. package/dist/commands/upload.d.ts +12 -0
  69. package/dist/commands/upload.d.ts.map +1 -0
  70. package/dist/commands/upload.js +158 -0
  71. package/dist/config/defaults.d.ts +21 -0
  72. package/dist/config/defaults.d.ts.map +1 -0
  73. package/dist/config/defaults.js +49 -0
  74. package/dist/config/loader.d.ts +66 -0
  75. package/dist/config/loader.d.ts.map +1 -0
  76. package/dist/config/loader.js +167 -0
  77. package/dist/config/schema.d.ts +55 -0
  78. package/dist/config/schema.d.ts.map +1 -0
  79. package/dist/config/schema.js +6 -0
  80. package/dist/index.d.ts +9 -0
  81. package/dist/index.d.ts.map +1 -0
  82. package/dist/index.js +1090 -0
  83. package/dist/interactive/fix-wizard.d.ts +44 -0
  84. package/dist/interactive/fix-wizard.d.ts.map +1 -0
  85. package/dist/interactive/fix-wizard.js +286 -0
  86. package/dist/interactive/init-wizard.d.ts +32 -0
  87. package/dist/interactive/init-wizard.d.ts.map +1 -0
  88. package/dist/interactive/init-wizard.js +193 -0
  89. package/dist/interactive/prompts.d.ts +62 -0
  90. package/dist/interactive/prompts.d.ts.map +1 -0
  91. package/dist/interactive/prompts.js +78 -0
  92. package/dist/monorepo/detector.d.ts +70 -0
  93. package/dist/monorepo/detector.d.ts.map +1 -0
  94. package/dist/monorepo/detector.js +278 -0
  95. package/dist/monorepo/index.d.ts +9 -0
  96. package/dist/monorepo/index.d.ts.map +1 -0
  97. package/dist/monorepo/index.js +8 -0
  98. package/dist/monorepo/workspace.d.ts +142 -0
  99. package/dist/monorepo/workspace.d.ts.map +1 -0
  100. package/dist/monorepo/workspace.js +171 -0
  101. package/dist/output/envelope.d.ts +21 -0
  102. package/dist/output/envelope.d.ts.map +1 -0
  103. package/dist/output/envelope.js +27 -0
  104. package/dist/output/factory.d.ts +73 -0
  105. package/dist/output/factory.d.ts.map +1 -0
  106. package/dist/output/factory.js +60 -0
  107. package/dist/output/formats.d.ts +11 -0
  108. package/dist/output/formats.d.ts.map +1 -0
  109. package/dist/output/formats.js +41 -0
  110. package/dist/output/html.d.ts +45 -0
  111. package/dist/output/html.d.ts.map +1 -0
  112. package/dist/output/html.js +607 -0
  113. package/dist/output/human.d.ts +41 -0
  114. package/dist/output/human.d.ts.map +1 -0
  115. package/dist/output/human.js +274 -0
  116. package/dist/output/json.d.ts +42 -0
  117. package/dist/output/json.d.ts.map +1 -0
  118. package/dist/output/json.js +37 -0
  119. package/dist/output/junit.d.ts +56 -0
  120. package/dist/output/junit.d.ts.map +1 -0
  121. package/dist/output/junit.js +135 -0
  122. package/dist/output/markdown.d.ts +77 -0
  123. package/dist/output/markdown.d.ts.map +1 -0
  124. package/dist/output/markdown.js +411 -0
  125. package/dist/output/sarif.d.ts +160 -0
  126. package/dist/output/sarif.d.ts.map +1 -0
  127. package/dist/output/sarif.js +207 -0
  128. package/dist/policy/evaluator.d.ts +111 -0
  129. package/dist/policy/evaluator.d.ts.map +1 -0
  130. package/dist/policy/evaluator.js +362 -0
  131. package/dist/policy/index.d.ts +15 -0
  132. package/dist/policy/index.d.ts.map +1 -0
  133. package/dist/policy/index.js +11 -0
  134. package/dist/policy/loader.d.ts +97 -0
  135. package/dist/policy/loader.d.ts.map +1 -0
  136. package/dist/policy/loader.js +281 -0
  137. package/dist/policy/schema.d.ts +297 -0
  138. package/dist/policy/schema.d.ts.map +1 -0
  139. package/dist/policy/schema.js +230 -0
  140. package/dist/quality-gate/evaluator.d.ts +58 -0
  141. package/dist/quality-gate/evaluator.d.ts.map +1 -0
  142. package/dist/quality-gate/evaluator.js +274 -0
  143. package/dist/quality-gate/index.d.ts +10 -0
  144. package/dist/quality-gate/index.d.ts.map +1 -0
  145. package/dist/quality-gate/index.js +7 -0
  146. package/dist/quality-gate/types.d.ts +103 -0
  147. package/dist/quality-gate/types.d.ts.map +1 -0
  148. package/dist/quality-gate/types.js +23 -0
  149. package/dist/templates/azure-devops.d.ts +25 -0
  150. package/dist/templates/azure-devops.d.ts.map +1 -0
  151. package/dist/templates/azure-devops.js +109 -0
  152. package/dist/templates/circleci.d.ts +28 -0
  153. package/dist/templates/circleci.d.ts.map +1 -0
  154. package/dist/templates/circleci.js +86 -0
  155. package/dist/templates/github-actions.d.ts +81 -0
  156. package/dist/templates/github-actions.d.ts.map +1 -0
  157. package/dist/templates/github-actions.js +393 -0
  158. package/dist/templates/gitlab-ci.d.ts +26 -0
  159. package/dist/templates/gitlab-ci.d.ts.map +1 -0
  160. package/dist/templates/gitlab-ci.js +70 -0
  161. package/dist/templates/index.d.ts +72 -0
  162. package/dist/templates/index.d.ts.map +1 -0
  163. package/dist/templates/index.js +112 -0
  164. package/dist/templates/jenkins.d.ts +26 -0
  165. package/dist/templates/jenkins.d.ts.map +1 -0
  166. package/dist/templates/jenkins.js +110 -0
  167. package/dist/ui/banner.d.ts +31 -0
  168. package/dist/ui/banner.d.ts.map +1 -0
  169. package/dist/ui/banner.js +84 -0
  170. package/dist/ui/diagnostics.d.ts +39 -0
  171. package/dist/ui/diagnostics.d.ts.map +1 -0
  172. package/dist/ui/diagnostics.js +153 -0
  173. package/dist/ui/spinner.d.ts +61 -0
  174. package/dist/ui/spinner.d.ts.map +1 -0
  175. package/dist/ui/spinner.js +101 -0
  176. package/dist/ui/table.d.ts +63 -0
  177. package/dist/ui/table.d.ts.map +1 -0
  178. package/dist/ui/table.js +236 -0
  179. package/dist/utils/client.d.ts +82 -0
  180. package/dist/utils/client.d.ts.map +1 -0
  181. package/dist/utils/client.js +128 -0
  182. package/dist/utils/detect-env.d.ts +59 -0
  183. package/dist/utils/detect-env.d.ts.map +1 -0
  184. package/dist/utils/detect-env.js +115 -0
  185. package/dist/utils/exit-codes.d.ts +47 -0
  186. package/dist/utils/exit-codes.d.ts.map +1 -0
  187. package/dist/utils/exit-codes.js +61 -0
  188. package/dist/utils/logger.d.ts +87 -0
  189. package/dist/utils/logger.d.ts.map +1 -0
  190. package/dist/utils/logger.js +185 -0
  191. package/dist/utils/sanitize.d.ts +36 -0
  192. package/dist/utils/sanitize.d.ts.map +1 -0
  193. package/dist/utils/sanitize.js +64 -0
  194. package/dist/utils/validators.d.ts +41 -0
  195. package/dist/utils/validators.d.ts.map +1 -0
  196. package/dist/utils/validators.js +123 -0
  197. package/package.json +63 -0
  198. package/schemas/vertaaux.config.schema.json +103 -0
@@ -0,0 +1,212 @@
1
+ /**
2
+ * Init command for VertaaUX CLI.
3
+ *
4
+ * Creates project configuration with guided wizard or defaults.
5
+ * Generates CI templates for popular platforms.
6
+ */
7
+ import fs from "fs";
8
+ import path from "path";
9
+ import chalk from "chalk";
10
+ import yaml from "yaml";
11
+ import { runInitWizard } from "../interactive/init-wizard.js";
12
+ import { isInteractive } from "../interactive/prompts.js";
13
+ import { ExitCode } from "../utils/exit-codes.js";
14
+ import { parseThreshold, parseFailOn } from "../utils/validators.js";
15
+ import { generateTemplate } from "../templates/index.js";
16
+ /**
17
+ * Config file path.
18
+ */
19
+ const CONFIG_FILE = ".vertaaux.yml";
20
+ /**
21
+ * Baseline directory.
22
+ */
23
+ const BASELINE_DIR = ".vertaaux";
24
+ // CI templates are now generated via templates/index.ts
25
+ /**
26
+ * Convert InitConfig to VertaauxConfig YAML format.
27
+ */
28
+ function configToYaml(config) {
29
+ const yamlConfig = {
30
+ // Header comment
31
+ $schema: "https://vertaaux.ai/schemas/config.json",
32
+ };
33
+ // Default URL
34
+ if (config.defaultUrl) {
35
+ yamlConfig.defaultUrl = config.defaultUrl;
36
+ }
37
+ // Audit mode
38
+ yamlConfig.mode = config.mode;
39
+ // Baseline rules section
40
+ if (config.failOn !== "none") {
41
+ yamlConfig.failOn = config.failOn;
42
+ }
43
+ if (config.threshold > 0) {
44
+ yamlConfig.threshold = config.threshold;
45
+ }
46
+ // Baseline config
47
+ yamlConfig.baseline = {
48
+ path: ".vertaaux/baseline.json",
49
+ autoUpdate: config.autoUpdateBaseline,
50
+ };
51
+ // Output config
52
+ yamlConfig.output = {
53
+ format: "auto",
54
+ groupBy: "severity",
55
+ };
56
+ // CI config
57
+ if (config.ciProvider !== "none") {
58
+ yamlConfig.ci = {
59
+ template: config.ciProvider,
60
+ };
61
+ }
62
+ // Generate YAML with comments
63
+ const header = `# VertaaUX Configuration
64
+ # https://vertaaux.ai/docs/cli/configuration
65
+ #
66
+ # Run \`vertaa audit\` to start auditing your site.
67
+ # Run \`vertaa init\` to regenerate this file.
68
+
69
+ `;
70
+ return header + yaml.stringify(yamlConfig);
71
+ }
72
+ /**
73
+ * Generate CI template file using unified template generator.
74
+ *
75
+ * @param provider - CI provider type
76
+ * @param config - Init configuration for workflow customization
77
+ * @returns Generated template with path, content, and optional instructions
78
+ */
79
+ function getCITemplate(provider, config) {
80
+ // Convert CITemplate to CIProvider (same type but import from templates)
81
+ const ciProvider = provider;
82
+ return generateTemplate(ciProvider, {
83
+ auditUrl: config?.defaultUrl,
84
+ failOn: config?.failOn === "none" ? "none" : (config?.failOn ?? "error"),
85
+ threshold: config?.threshold ?? 0,
86
+ uploadSarif: true,
87
+ uploadArtifacts: true,
88
+ postComment: true,
89
+ });
90
+ }
91
+ /**
92
+ * Write file, creating directories as needed.
93
+ */
94
+ function writeFile(filePath, content) {
95
+ const resolvedPath = path.resolve(process.cwd(), filePath);
96
+ const dir = path.dirname(resolvedPath);
97
+ if (!fs.existsSync(dir)) {
98
+ fs.mkdirSync(dir, { recursive: true });
99
+ }
100
+ fs.writeFileSync(resolvedPath, content, "utf-8");
101
+ }
102
+ /**
103
+ * Check if a file already exists and prompt for overwrite.
104
+ */
105
+ function checkExisting(filePath) {
106
+ const resolvedPath = path.resolve(process.cwd(), filePath);
107
+ return fs.existsSync(resolvedPath);
108
+ }
109
+ /**
110
+ * Handle the init command.
111
+ */
112
+ async function handleInit(options) {
113
+ // Check for existing config
114
+ if (checkExisting(CONFIG_FILE) && !options.force) {
115
+ console.error(chalk.yellow(`Configuration file ${CONFIG_FILE} already exists.`));
116
+ console.error("Use --force to overwrite.");
117
+ process.exit(ExitCode.ERROR);
118
+ }
119
+ let config;
120
+ // Determine configuration source
121
+ if (options.yes || !isInteractive()) {
122
+ // Use defaults
123
+ config = {
124
+ mode: "standard",
125
+ failOn: options.failOn || "error",
126
+ threshold: options.threshold ?? 0,
127
+ autoUpdateBaseline: false,
128
+ ciProvider: options.ci || "none",
129
+ };
130
+ }
131
+ else {
132
+ // Run interactive wizard
133
+ try {
134
+ config = await runInitWizard();
135
+ }
136
+ catch (error) {
137
+ if (error instanceof Error && error.message.includes("cancelled")) {
138
+ console.error("Initialization cancelled.");
139
+ process.exit(0);
140
+ }
141
+ throw error;
142
+ }
143
+ }
144
+ // Override with explicit flags
145
+ if (options.ci) {
146
+ config.ciProvider = options.ci;
147
+ }
148
+ if (options.failOn) {
149
+ config.failOn = options.failOn;
150
+ }
151
+ if (options.threshold !== undefined) {
152
+ config.threshold = options.threshold;
153
+ }
154
+ // Create .vertaaux directory
155
+ const baselineDir = path.resolve(process.cwd(), BASELINE_DIR);
156
+ if (!fs.existsSync(baselineDir)) {
157
+ fs.mkdirSync(baselineDir, { recursive: true });
158
+ }
159
+ // Write config file
160
+ const yamlContent = configToYaml(config);
161
+ writeFile(CONFIG_FILE, yamlContent);
162
+ console.error(chalk.green(`Created ${CONFIG_FILE}`));
163
+ // Generate CI template if selected
164
+ if (config.ciProvider !== "none") {
165
+ const template = getCITemplate(config.ciProvider, config);
166
+ if (template) {
167
+ writeFile(template.path, template.content);
168
+ console.error(chalk.green(`Created ${template.path}`));
169
+ // Show instructions if provided by template generator
170
+ if (template.instructions) {
171
+ console.error("");
172
+ console.error(chalk.cyan(`Note: ${template.instructions}`));
173
+ }
174
+ }
175
+ }
176
+ // Success message
177
+ console.error("");
178
+ console.error(chalk.green("VertaaUX initialized successfully!"));
179
+ console.error("");
180
+ console.error("Next steps:");
181
+ console.error(` 1. ${chalk.cyan("vertaa audit")} - Run your first audit`);
182
+ if (config.ciProvider === "github") {
183
+ console.error(` 2. Add ${chalk.cyan("VERTAAUX_API_KEY")} to GitHub Secrets`);
184
+ }
185
+ else if (config.ciProvider !== "none") {
186
+ console.error(` 2. Add ${chalk.cyan("VERTAAUX_API_KEY")} to your CI environment`);
187
+ }
188
+ console.error(` 3. ${chalk.cyan("vertaa baseline create")} - Create baseline for existing issues`);
189
+ console.error("");
190
+ }
191
+ /**
192
+ * Register the init command with the Commander program.
193
+ */
194
+ export function registerInitCommand(program) {
195
+ program
196
+ .command("init")
197
+ .description("Initialize VertaaUX configuration for your project")
198
+ .option("-y, --yes", "Skip prompts, use defaults")
199
+ .option("--ci <provider>", "CI provider: github|gitlab|circleci|azure|jenkins|none")
200
+ .option("--fail-on <severity>", "Fail CI on severity: error|warning|info (default: error)", parseFailOn)
201
+ .option("--threshold <score>", "Minimum score threshold (0-100)", parseThreshold)
202
+ .option("-f, --force", "Overwrite existing configuration")
203
+ .action(async (options) => {
204
+ try {
205
+ await handleInit(options);
206
+ }
207
+ catch (error) {
208
+ console.error(chalk.red("Error:"), error instanceof Error ? error.message : String(error));
209
+ process.exit(ExitCode.ERROR);
210
+ }
211
+ });
212
+ }
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Authentication commands for VertaaUX CLI.
3
+ *
4
+ * Commands:
5
+ * - vertaa login: Authenticate via device code flow or CI token
6
+ * - vertaa logout: Clear stored credentials
7
+ * - vertaa whoami: Show current authentication status
8
+ */
9
+ import type { Command } from "commander";
10
+ /**
11
+ * Register authentication commands with the Commander program.
12
+ */
13
+ export declare function registerLoginCommand(program: Command): void;
14
+ //# sourceMappingURL=login.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"login.d.ts","sourceRoot":"","sources":["../../src/commands/login.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA6OzC;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CA+B3D"}
@@ -0,0 +1,222 @@
1
+ /**
2
+ * Authentication commands for VertaaUX CLI.
3
+ *
4
+ * Commands:
5
+ * - vertaa login: Authenticate via device code flow or CI token
6
+ * - vertaa logout: Clear stored credentials
7
+ * - vertaa whoami: Show current authentication status
8
+ */
9
+ import chalk from "chalk";
10
+ import { saveToken, loadToken, clearToken, isTokenExpired, } from "../auth/token-store.js";
11
+ import { startDeviceFlow } from "../auth/device-flow.js";
12
+ import { validateCIToken, getCIToken, getTokenInfo } from "../auth/ci-token.js";
13
+ import { isInteractive } from "../interactive/prompts.js";
14
+ import { ExitCode } from "../utils/exit-codes.js";
15
+ /**
16
+ * OAuth client ID for the CLI.
17
+ * This is a public client ID, not a secret.
18
+ */
19
+ const CLI_CLIENT_ID = "vertaaux-cli";
20
+ /**
21
+ * Default API base URL.
22
+ */
23
+ const DEFAULT_API_BASE = "https://vertaaux.ai/v1";
24
+ /**
25
+ * Default auth base URL.
26
+ */
27
+ const DEFAULT_AUTH_BASE = "https://vertaaux.ai";
28
+ /**
29
+ * Get the auth base URL from environment or default.
30
+ */
31
+ function getAuthBase() {
32
+ return process.env.VERTAAUX_AUTH_BASE || DEFAULT_AUTH_BASE;
33
+ }
34
+ /**
35
+ * Get the API base URL from environment or default.
36
+ */
37
+ function getApiBase() {
38
+ return (process.env.VERTAAUX_API_BASE?.replace(/\/$/, "") || DEFAULT_API_BASE);
39
+ }
40
+ /**
41
+ * Handle the login command.
42
+ */
43
+ async function handleLogin(options) {
44
+ // Check for SSO placeholder
45
+ if (options.sso) {
46
+ console.error("SSO login is not yet implemented.");
47
+ console.error("Use --token for CI/API token authentication or omit flags for device code flow.");
48
+ process.exit(ExitCode.ERROR);
49
+ }
50
+ // Option 1: Direct token authentication (CI mode)
51
+ if (options.token) {
52
+ console.error("Validating token...");
53
+ const apiBase = options.base || getApiBase();
54
+ const isValid = await validateCIToken(options.token, apiBase);
55
+ if (!isValid) {
56
+ console.error(chalk.red("Error: Invalid token. Please check your token and try again."));
57
+ process.exit(ExitCode.ERROR);
58
+ }
59
+ // Save the CI token
60
+ const tokenData = {
61
+ accessToken: options.token,
62
+ type: "ci",
63
+ savedAt: new Date().toISOString(),
64
+ };
65
+ await saveToken(tokenData);
66
+ console.error(chalk.green("Authentication successful!"));
67
+ console.error("Token saved to ~/.vertaaux/credentials.json");
68
+ return;
69
+ }
70
+ // Option 2: Check for CI token in environment
71
+ const envToken = getCIToken();
72
+ if (envToken && !isInteractive()) {
73
+ console.error("Found token in environment, validating...");
74
+ const apiBase = options.base || getApiBase();
75
+ const isValid = await validateCIToken(envToken, apiBase);
76
+ if (!isValid) {
77
+ console.error(chalk.red("Error: Environment token is invalid."));
78
+ process.exit(ExitCode.ERROR);
79
+ }
80
+ const tokenData = {
81
+ accessToken: envToken,
82
+ type: "ci",
83
+ savedAt: new Date().toISOString(),
84
+ };
85
+ await saveToken(tokenData);
86
+ console.error(chalk.green("Authentication successful!"));
87
+ console.error("Token from environment saved to ~/.vertaaux/credentials.json");
88
+ return;
89
+ }
90
+ // Option 3: Interactive device code flow (requires TTY)
91
+ if (!isInteractive()) {
92
+ console.error(chalk.red("Error: Interactive login requires a terminal."));
93
+ console.error("Use --token <token> for non-interactive authentication,");
94
+ console.error("or set VERTAAUX_TOKEN environment variable.");
95
+ process.exit(ExitCode.ERROR);
96
+ }
97
+ // Start device code flow
98
+ console.error("Starting authentication...");
99
+ try {
100
+ const authBase = options.base ? options.base.replace("/v1", "") : getAuthBase();
101
+ const result = await startDeviceFlow(CLI_CLIENT_ID, authBase);
102
+ // Calculate expiration time
103
+ const expiresAt = new Date(Date.now() + result.expiresIn * 1000).toISOString();
104
+ // Save token
105
+ const tokenData = {
106
+ accessToken: result.accessToken,
107
+ refreshToken: result.refreshToken,
108
+ expiresAt,
109
+ type: "device",
110
+ savedAt: new Date().toISOString(),
111
+ };
112
+ await saveToken(tokenData);
113
+ console.error(chalk.green("\nAuthentication successful!"));
114
+ console.error("Token saved to ~/.vertaaux/credentials.json");
115
+ }
116
+ catch (error) {
117
+ console.error(chalk.red("\nError:"), error instanceof Error ? error.message : String(error));
118
+ process.exit(ExitCode.ERROR);
119
+ }
120
+ }
121
+ /**
122
+ * Handle the logout command.
123
+ */
124
+ async function handleLogout() {
125
+ const existingToken = await loadToken();
126
+ if (!existingToken) {
127
+ console.error("No stored credentials found.");
128
+ return;
129
+ }
130
+ await clearToken();
131
+ console.error(chalk.green("Logged out successfully."));
132
+ console.error("Credentials removed from ~/.vertaaux/credentials.json");
133
+ }
134
+ /**
135
+ * Handle the whoami command.
136
+ */
137
+ async function handleWhoami(options) {
138
+ // Check for token in credentials file
139
+ const storedToken = await loadToken();
140
+ // Check for token in environment
141
+ const envToken = getCIToken();
142
+ if (!storedToken && !envToken) {
143
+ console.error(chalk.yellow("Not authenticated."));
144
+ console.error("\nRun `vertaa login` to authenticate.");
145
+ return;
146
+ }
147
+ // Use stored token or env token
148
+ const token = storedToken?.accessToken || envToken;
149
+ const tokenSource = storedToken ? "stored" : "environment";
150
+ if (!token) {
151
+ console.error(chalk.yellow("Not authenticated."));
152
+ console.error("\nRun `vertaa login` to authenticate.");
153
+ return;
154
+ }
155
+ // Check expiration for stored device tokens
156
+ if (storedToken && storedToken.type === "device" && isTokenExpired(storedToken)) {
157
+ console.error(chalk.yellow("Token expired."));
158
+ console.error("\nRun `vertaa login` to re-authenticate.");
159
+ return;
160
+ }
161
+ // Get token info from API
162
+ const apiBase = options.base || getApiBase();
163
+ const info = await getTokenInfo(token, apiBase);
164
+ if (!info || !info.valid) {
165
+ console.error(chalk.yellow("Token invalid or expired."));
166
+ console.error("\nRun `vertaa login` to re-authenticate.");
167
+ return;
168
+ }
169
+ // Display auth status
170
+ console.error(chalk.green("Authenticated"));
171
+ console.error("");
172
+ console.error(` Source: ${tokenSource}`);
173
+ console.error(` Type: ${storedToken?.type || "ci"}`);
174
+ if (info.organization) {
175
+ console.error(` Organization: ${info.organization}`);
176
+ }
177
+ if (info.user_id) {
178
+ console.error(` User ID: ${info.user_id}`);
179
+ }
180
+ if (info.scopes && info.scopes.length > 0) {
181
+ console.error(` Scopes: ${info.scopes.join(", ")}`);
182
+ }
183
+ if (storedToken?.expiresAt) {
184
+ const expiresAt = new Date(storedToken.expiresAt);
185
+ const now = new Date();
186
+ const diffMs = expiresAt.getTime() - now.getTime();
187
+ const diffHours = Math.round(diffMs / (1000 * 60 * 60));
188
+ if (diffHours > 0) {
189
+ console.error(` Expires: in ${diffHours} hour${diffHours === 1 ? "" : "s"}`);
190
+ }
191
+ }
192
+ }
193
+ /**
194
+ * Register authentication commands with the Commander program.
195
+ */
196
+ export function registerLoginCommand(program) {
197
+ // Login command
198
+ program
199
+ .command("login")
200
+ .description("Authenticate with VertaaUX")
201
+ .option("--token <token>", "Use API token directly (for CI/non-interactive use)")
202
+ .option("--sso", "Use SSO login (not yet implemented)")
203
+ .option("-b, --base <url>", "API base URL")
204
+ .action(async (options) => {
205
+ await handleLogin(options);
206
+ });
207
+ // Logout command
208
+ program
209
+ .command("logout")
210
+ .description("Clear stored credentials")
211
+ .action(async () => {
212
+ await handleLogout();
213
+ });
214
+ // Whoami command
215
+ program
216
+ .command("whoami")
217
+ .description("Show current authentication status")
218
+ .option("-b, --base <url>", "API base URL")
219
+ .action(async (options) => {
220
+ await handleWhoami(options);
221
+ });
222
+ }
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Policy management commands for VertaaUX CLI.
3
+ *
4
+ * Provides commands to initialize, validate, and display policy files.
5
+ *
6
+ * Implements CICD-17: Policy-as-code support.
7
+ */
8
+ import { Command } from "commander";
9
+ /**
10
+ * Register the policy command with the Commander program.
11
+ */
12
+ export declare function registerPolicyCommand(program: Command): void;
13
+ //# sourceMappingURL=policy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"policy.d.ts","sourceRoot":"","sources":["../../src/commands/policy.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAuWpC;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CA8E5D"}