@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.
- package/README.md +345 -0
- package/dist/auth/ci-token.d.ts +49 -0
- package/dist/auth/ci-token.d.ts.map +1 -0
- package/dist/auth/ci-token.js +83 -0
- package/dist/auth/device-flow.d.ts +66 -0
- package/dist/auth/device-flow.d.ts.map +1 -0
- package/dist/auth/device-flow.js +156 -0
- package/dist/auth/token-store.d.ts +53 -0
- package/dist/auth/token-store.d.ts.map +1 -0
- package/dist/auth/token-store.js +78 -0
- package/dist/baseline/diff.d.ts +57 -0
- package/dist/baseline/diff.d.ts.map +1 -0
- package/dist/baseline/diff.js +152 -0
- package/dist/baseline/hash.d.ts +54 -0
- package/dist/baseline/hash.d.ts.map +1 -0
- package/dist/baseline/hash.js +66 -0
- package/dist/baseline/manager.d.ts +89 -0
- package/dist/baseline/manager.d.ts.map +1 -0
- package/dist/baseline/manager.js +157 -0
- package/dist/cache/index.d.ts +8 -0
- package/dist/cache/index.d.ts.map +1 -0
- package/dist/cache/index.js +7 -0
- package/dist/cache/route-cache.d.ts +119 -0
- package/dist/cache/route-cache.d.ts.map +1 -0
- package/dist/cache/route-cache.js +213 -0
- package/dist/ci/changed-routes.d.ts +95 -0
- package/dist/ci/changed-routes.d.ts.map +1 -0
- package/dist/ci/changed-routes.js +304 -0
- package/dist/ci/github-api.d.ts +68 -0
- package/dist/ci/github-api.d.ts.map +1 -0
- package/dist/ci/github-api.js +138 -0
- package/dist/ci/gitlab-api.d.ts +75 -0
- package/dist/ci/gitlab-api.d.ts.map +1 -0
- package/dist/ci/gitlab-api.js +180 -0
- package/dist/ci/index.d.ts +6 -0
- package/dist/ci/index.d.ts.map +1 -0
- package/dist/ci/index.js +4 -0
- package/dist/commands/audit.d.ts +58 -0
- package/dist/commands/audit.d.ts.map +1 -0
- package/dist/commands/audit.js +862 -0
- package/dist/commands/baseline.d.ts +22 -0
- package/dist/commands/baseline.d.ts.map +1 -0
- package/dist/commands/baseline.js +210 -0
- package/dist/commands/comment.d.ts +14 -0
- package/dist/commands/comment.d.ts.map +1 -0
- package/dist/commands/comment.js +363 -0
- package/dist/commands/diff.d.ts +24 -0
- package/dist/commands/diff.d.ts.map +1 -0
- package/dist/commands/diff.js +196 -0
- package/dist/commands/doctor.d.ts +58 -0
- package/dist/commands/doctor.d.ts.map +1 -0
- package/dist/commands/doctor.js +338 -0
- package/dist/commands/download.d.ts +12 -0
- package/dist/commands/download.d.ts.map +1 -0
- package/dist/commands/download.js +183 -0
- package/dist/commands/explain.d.ts +62 -0
- package/dist/commands/explain.d.ts.map +1 -0
- package/dist/commands/explain.js +302 -0
- package/dist/commands/init.d.ts +12 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +212 -0
- package/dist/commands/login.d.ts +14 -0
- package/dist/commands/login.d.ts.map +1 -0
- package/dist/commands/login.js +222 -0
- package/dist/commands/policy.d.ts +13 -0
- package/dist/commands/policy.d.ts.map +1 -0
- package/dist/commands/policy.js +347 -0
- package/dist/commands/upload.d.ts +12 -0
- package/dist/commands/upload.d.ts.map +1 -0
- package/dist/commands/upload.js +158 -0
- package/dist/config/defaults.d.ts +21 -0
- package/dist/config/defaults.d.ts.map +1 -0
- package/dist/config/defaults.js +49 -0
- package/dist/config/loader.d.ts +66 -0
- package/dist/config/loader.d.ts.map +1 -0
- package/dist/config/loader.js +167 -0
- package/dist/config/schema.d.ts +55 -0
- package/dist/config/schema.d.ts.map +1 -0
- package/dist/config/schema.js +6 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1090 -0
- package/dist/interactive/fix-wizard.d.ts +44 -0
- package/dist/interactive/fix-wizard.d.ts.map +1 -0
- package/dist/interactive/fix-wizard.js +286 -0
- package/dist/interactive/init-wizard.d.ts +32 -0
- package/dist/interactive/init-wizard.d.ts.map +1 -0
- package/dist/interactive/init-wizard.js +193 -0
- package/dist/interactive/prompts.d.ts +62 -0
- package/dist/interactive/prompts.d.ts.map +1 -0
- package/dist/interactive/prompts.js +78 -0
- package/dist/monorepo/detector.d.ts +70 -0
- package/dist/monorepo/detector.d.ts.map +1 -0
- package/dist/monorepo/detector.js +278 -0
- package/dist/monorepo/index.d.ts +9 -0
- package/dist/monorepo/index.d.ts.map +1 -0
- package/dist/monorepo/index.js +8 -0
- package/dist/monorepo/workspace.d.ts +142 -0
- package/dist/monorepo/workspace.d.ts.map +1 -0
- package/dist/monorepo/workspace.js +171 -0
- package/dist/output/envelope.d.ts +21 -0
- package/dist/output/envelope.d.ts.map +1 -0
- package/dist/output/envelope.js +27 -0
- package/dist/output/factory.d.ts +73 -0
- package/dist/output/factory.d.ts.map +1 -0
- package/dist/output/factory.js +60 -0
- package/dist/output/formats.d.ts +11 -0
- package/dist/output/formats.d.ts.map +1 -0
- package/dist/output/formats.js +41 -0
- package/dist/output/html.d.ts +45 -0
- package/dist/output/html.d.ts.map +1 -0
- package/dist/output/html.js +607 -0
- package/dist/output/human.d.ts +41 -0
- package/dist/output/human.d.ts.map +1 -0
- package/dist/output/human.js +274 -0
- package/dist/output/json.d.ts +42 -0
- package/dist/output/json.d.ts.map +1 -0
- package/dist/output/json.js +37 -0
- package/dist/output/junit.d.ts +56 -0
- package/dist/output/junit.d.ts.map +1 -0
- package/dist/output/junit.js +135 -0
- package/dist/output/markdown.d.ts +77 -0
- package/dist/output/markdown.d.ts.map +1 -0
- package/dist/output/markdown.js +411 -0
- package/dist/output/sarif.d.ts +160 -0
- package/dist/output/sarif.d.ts.map +1 -0
- package/dist/output/sarif.js +207 -0
- package/dist/policy/evaluator.d.ts +111 -0
- package/dist/policy/evaluator.d.ts.map +1 -0
- package/dist/policy/evaluator.js +362 -0
- package/dist/policy/index.d.ts +15 -0
- package/dist/policy/index.d.ts.map +1 -0
- package/dist/policy/index.js +11 -0
- package/dist/policy/loader.d.ts +97 -0
- package/dist/policy/loader.d.ts.map +1 -0
- package/dist/policy/loader.js +281 -0
- package/dist/policy/schema.d.ts +297 -0
- package/dist/policy/schema.d.ts.map +1 -0
- package/dist/policy/schema.js +230 -0
- package/dist/quality-gate/evaluator.d.ts +58 -0
- package/dist/quality-gate/evaluator.d.ts.map +1 -0
- package/dist/quality-gate/evaluator.js +274 -0
- package/dist/quality-gate/index.d.ts +10 -0
- package/dist/quality-gate/index.d.ts.map +1 -0
- package/dist/quality-gate/index.js +7 -0
- package/dist/quality-gate/types.d.ts +103 -0
- package/dist/quality-gate/types.d.ts.map +1 -0
- package/dist/quality-gate/types.js +23 -0
- package/dist/templates/azure-devops.d.ts +25 -0
- package/dist/templates/azure-devops.d.ts.map +1 -0
- package/dist/templates/azure-devops.js +109 -0
- package/dist/templates/circleci.d.ts +28 -0
- package/dist/templates/circleci.d.ts.map +1 -0
- package/dist/templates/circleci.js +86 -0
- package/dist/templates/github-actions.d.ts +81 -0
- package/dist/templates/github-actions.d.ts.map +1 -0
- package/dist/templates/github-actions.js +393 -0
- package/dist/templates/gitlab-ci.d.ts +26 -0
- package/dist/templates/gitlab-ci.d.ts.map +1 -0
- package/dist/templates/gitlab-ci.js +70 -0
- package/dist/templates/index.d.ts +72 -0
- package/dist/templates/index.d.ts.map +1 -0
- package/dist/templates/index.js +112 -0
- package/dist/templates/jenkins.d.ts +26 -0
- package/dist/templates/jenkins.d.ts.map +1 -0
- package/dist/templates/jenkins.js +110 -0
- package/dist/ui/banner.d.ts +31 -0
- package/dist/ui/banner.d.ts.map +1 -0
- package/dist/ui/banner.js +84 -0
- package/dist/ui/diagnostics.d.ts +39 -0
- package/dist/ui/diagnostics.d.ts.map +1 -0
- package/dist/ui/diagnostics.js +153 -0
- package/dist/ui/spinner.d.ts +61 -0
- package/dist/ui/spinner.d.ts.map +1 -0
- package/dist/ui/spinner.js +101 -0
- package/dist/ui/table.d.ts +63 -0
- package/dist/ui/table.d.ts.map +1 -0
- package/dist/ui/table.js +236 -0
- package/dist/utils/client.d.ts +82 -0
- package/dist/utils/client.d.ts.map +1 -0
- package/dist/utils/client.js +128 -0
- package/dist/utils/detect-env.d.ts +59 -0
- package/dist/utils/detect-env.d.ts.map +1 -0
- package/dist/utils/detect-env.js +115 -0
- package/dist/utils/exit-codes.d.ts +47 -0
- package/dist/utils/exit-codes.d.ts.map +1 -0
- package/dist/utils/exit-codes.js +61 -0
- package/dist/utils/logger.d.ts +87 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +185 -0
- package/dist/utils/sanitize.d.ts +36 -0
- package/dist/utils/sanitize.d.ts.map +1 -0
- package/dist/utils/sanitize.js +64 -0
- package/dist/utils/validators.d.ts +41 -0
- package/dist/utils/validators.d.ts.map +1 -0
- package/dist/utils/validators.js +123 -0
- package/package.json +63 -0
- 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"}
|