osv-security-cli 0.1.0 → 0.1.1
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/dist/bin/osv-security.js +96 -79
- package/dist/bin/osv-security.js.map +1 -1
- package/dist/src/index.d.ts +7 -2
- package/dist/src/index.js +73 -75
- package/dist/src/index.js.map +1 -1
- package/package.json +2 -2
package/dist/bin/osv-security.js
CHANGED
|
@@ -25,6 +25,7 @@ var RuntimeConfigSchema = z.object({
|
|
|
25
25
|
package_manager_js: z.string(),
|
|
26
26
|
execution: z.enum(["docker", "local"]),
|
|
27
27
|
docker_service: z.string(),
|
|
28
|
+
docker_workdir: z.string().optional(),
|
|
28
29
|
test_command: z.string(),
|
|
29
30
|
build_commands: z.object({
|
|
30
31
|
frontend: z.string(),
|
|
@@ -82,7 +83,7 @@ var GateValidationError = class extends Error {
|
|
|
82
83
|
};
|
|
83
84
|
|
|
84
85
|
// src/config/loader.ts
|
|
85
|
-
var DEFAULT_CONFIG_PATH = "
|
|
86
|
+
var DEFAULT_CONFIG_PATH = "project-config.yml";
|
|
86
87
|
async function loadConfig(configPath, cwd = process.cwd()) {
|
|
87
88
|
const absolutePath = resolve(cwd, configPath);
|
|
88
89
|
let raw;
|
|
@@ -116,70 +117,66 @@ ${issues}`,
|
|
|
116
117
|
}
|
|
117
118
|
|
|
118
119
|
// src/config/generator.ts
|
|
119
|
-
import { stringify } from "yaml";
|
|
120
120
|
function generateConfigYaml(opts = {}) {
|
|
121
|
-
const
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
""
|
|
181
|
-
].join("\n");
|
|
182
|
-
return header + stringify(config, { lineWidth: 0 });
|
|
121
|
+
const projectName = opts.projectName ?? "My Laravel Project";
|
|
122
|
+
const client = opts.client ?? "Client Name";
|
|
123
|
+
const execution = opts.execution ?? "docker";
|
|
124
|
+
const dockerService = opts.dockerService ?? "app";
|
|
125
|
+
const dockerWorkdir = opts.dockerWorkdir;
|
|
126
|
+
const phpVersion = opts.phpVersion ?? "8.2";
|
|
127
|
+
const laravelVersion = opts.laravelVersion ?? "10.x";
|
|
128
|
+
const nodeVersion = opts.nodeVersion ?? "20.x";
|
|
129
|
+
const testCommand = opts.testCommand ?? "php artisan test --compact";
|
|
130
|
+
const frontendBuild = opts.frontendBuildCommand ?? "npm run development-frontend";
|
|
131
|
+
const backendBuild = opts.backendBuildCommand ?? "npm run development-backend";
|
|
132
|
+
const workdirLine = dockerWorkdir ? `
|
|
133
|
+
docker_workdir: '${dockerWorkdir}'` : "";
|
|
134
|
+
return `# OSV Security CLI \u2014 project configuration
|
|
135
|
+
# Generated by: osv-security init
|
|
136
|
+
# Documentation: https://github.com/google/osv-scanner
|
|
137
|
+
#
|
|
138
|
+
# protected_packages: packages that must NEVER be auto-upgraded beyond their stated constraint.
|
|
139
|
+
# Any update requiring a constraint change needs explicit per-package authorization.
|
|
140
|
+
# safe_update_policy: patch/minor updates within existing constraints are auto-safe.
|
|
141
|
+
|
|
142
|
+
project:
|
|
143
|
+
name: '${projectName}'
|
|
144
|
+
client: '${client}'
|
|
145
|
+
|
|
146
|
+
runtime:
|
|
147
|
+
php: '${phpVersion}'
|
|
148
|
+
laravel: '${laravelVersion}'
|
|
149
|
+
node: '${nodeVersion}'
|
|
150
|
+
package_manager_php: 'composer'
|
|
151
|
+
package_manager_js: 'npm'
|
|
152
|
+
execution: '${execution}'
|
|
153
|
+
docker_service: '${dockerService}'${workdirLine}
|
|
154
|
+
test_command: '${testCommand}'
|
|
155
|
+
build_commands:
|
|
156
|
+
frontend: '${frontendBuild}'
|
|
157
|
+
backend: '${backendBuild}'
|
|
158
|
+
|
|
159
|
+
# Add packages that must not be auto-upgraded beyond their constraint.
|
|
160
|
+
# Examples:
|
|
161
|
+
# composer:
|
|
162
|
+
# - package: 'laravel/framework'
|
|
163
|
+
# constraint: '^10.0'
|
|
164
|
+
# reason: 'Major upgrade to Laravel 11 requires a dedicated project'
|
|
165
|
+
# npm:
|
|
166
|
+
# - package: 'tailwindcss'
|
|
167
|
+
# constraint: '^3.3.3'
|
|
168
|
+
# reason: 'Tailwind v4 has breaking config changes'
|
|
169
|
+
protected_packages:
|
|
170
|
+
composer: []
|
|
171
|
+
npm: []
|
|
172
|
+
|
|
173
|
+
safe_update_policy:
|
|
174
|
+
allow_patch_and_minor_within_constraints: true
|
|
175
|
+
require_authorization_for_constraint_change: true
|
|
176
|
+
authorization_format: 'sim, confirmo breaking changes para [vendor/pacote]'
|
|
177
|
+
|
|
178
|
+
conflict_resolution: 'stop_and_ask'
|
|
179
|
+
`;
|
|
183
180
|
}
|
|
184
181
|
|
|
185
182
|
// src/executor/local-executor.ts
|
|
@@ -233,19 +230,19 @@ var DockerExecutor = class {
|
|
|
233
230
|
constructor(service, options = {}) {
|
|
234
231
|
this.service = service;
|
|
235
232
|
this.dryRun = options.dryRun ?? false;
|
|
233
|
+
this.workdir = options.workdir;
|
|
236
234
|
}
|
|
237
235
|
dryRun;
|
|
238
236
|
environment = "docker";
|
|
237
|
+
workdir;
|
|
238
|
+
buildDockerCommand(command) {
|
|
239
|
+
const workdirFlag = this.workdir ? `--workdir ${this.workdir} ` : "";
|
|
240
|
+
return `docker-compose exec -T ${workdirFlag}${this.service} sh -c "${command.replace(/"/g, '\\"')}"`;
|
|
241
|
+
}
|
|
239
242
|
async run(command, options = {}) {
|
|
240
|
-
const dockerCommand =
|
|
243
|
+
const dockerCommand = this.buildDockerCommand(command);
|
|
241
244
|
if (this.dryRun) {
|
|
242
|
-
return {
|
|
243
|
-
stdout: "",
|
|
244
|
-
stderr: "",
|
|
245
|
-
exitCode: 0,
|
|
246
|
-
command: dockerCommand,
|
|
247
|
-
dryRun: true
|
|
248
|
-
};
|
|
245
|
+
return { stdout: "", stderr: "", exitCode: 0, command: dockerCommand, dryRun: true };
|
|
249
246
|
}
|
|
250
247
|
try {
|
|
251
248
|
const result = await execa2(dockerCommand, {
|
|
@@ -313,7 +310,7 @@ var logger = {
|
|
|
313
310
|
};
|
|
314
311
|
|
|
315
312
|
// src/environment/detector.ts
|
|
316
|
-
async function detectEnvironment(preferredEnv, dockerService, cwd, dryRun = false) {
|
|
313
|
+
async function detectEnvironment(preferredEnv, dockerService, cwd, dryRun = false, dockerWorkdir) {
|
|
317
314
|
if (preferredEnv === "local") {
|
|
318
315
|
logger.debug("Using local execution (configured preference)");
|
|
319
316
|
return new LocalExecutor({ dryRun });
|
|
@@ -324,8 +321,9 @@ async function detectEnvironment(preferredEnv, dockerService, cwd, dryRun = fals
|
|
|
324
321
|
{ cwd }
|
|
325
322
|
);
|
|
326
323
|
if (result.exitCode === 0 && parseInt(result.stdout.trim(), 10) > 0) {
|
|
327
|
-
|
|
328
|
-
|
|
324
|
+
const workdirInfo = dockerWorkdir ? ` (workdir: ${dockerWorkdir})` : "";
|
|
325
|
+
logger.debug(`Using Docker execution (service: ${dockerService}${workdirInfo})`);
|
|
326
|
+
return new DockerExecutor(dockerService, { dryRun, workdir: dockerWorkdir });
|
|
329
327
|
}
|
|
330
328
|
logger.warn(`Docker service "${dockerService}" not running \u2014 falling back to local execution`);
|
|
331
329
|
return new LocalExecutor({ dryRun });
|
|
@@ -1085,11 +1083,24 @@ function executiveReportFilename(client, project) {
|
|
|
1085
1083
|
return `[${client} ${project}] Report OSV Scanner - ${year}-${month} - ${monthEn}.md`;
|
|
1086
1084
|
}
|
|
1087
1085
|
|
|
1086
|
+
// src/utils/prompt.ts
|
|
1087
|
+
import { createInterface } from "readline/promises";
|
|
1088
|
+
async function prompt(question, defaultValue) {
|
|
1089
|
+
const hint = defaultValue ? ` (default: ${defaultValue})` : "";
|
|
1090
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
1091
|
+
try {
|
|
1092
|
+
const answer = await rl.question(`${question}${hint}: `);
|
|
1093
|
+
return answer.trim() || defaultValue || "";
|
|
1094
|
+
} finally {
|
|
1095
|
+
rl.close();
|
|
1096
|
+
}
|
|
1097
|
+
}
|
|
1098
|
+
|
|
1088
1099
|
// bin/osv-security.ts
|
|
1089
1100
|
var program = new Command();
|
|
1090
1101
|
program.name("osv-security").description("OSV vulnerability scanning and safe dependency update CLI").version("0.1.0");
|
|
1091
1102
|
var commonOptions = (cmd) => cmd.option("-c, --config <path>", "Path to project-config.yml", DEFAULT_CONFIG_PATH).option("--cwd <path>", "Working directory", process.cwd()).option("--dry-run", "Show commands without executing", false).option("-v, --verbose", "Verbose output", false).option("-q, --quiet", "Suppress all output except errors and final report", false).option("--json", "Output results as JSON", false).option("-o, --output <path>", "Write report to file");
|
|
1092
|
-
program.command("init").description("Generate a project-config.yml template in the current project").option("--project-name <name>", "Project name").option("--client <name>", "Client name").option("--execution <mode>", "Execution mode: docker or local", "docker").option("--docker-service <service>", "Docker Compose service name", "app").option("--php-version <version>", "PHP version", "8.2").option("--laravel-version <version>", "Laravel version", "10.x").option("--node-version <version>", "Node.js version", "20.x").option("--test-command <cmd>", "Test command", "php artisan test --compact").option("--cwd <path>", "Working directory", process.cwd()).option("--output <path>", "Output path (default: .github/agents/project-config.yml)").option("--force", "Overwrite existing file", false).action(async (opts) => {
|
|
1103
|
+
program.command("init").description("Generate a project-config.yml template in the current project").option("--project-name <name>", "Project name").option("--client <name>", "Client name").option("--execution <mode>", "Execution mode: docker or local", "docker").option("--docker-service <service>", "Docker Compose service name", "app").option("--docker-workdir <path>", "Working directory inside the container (e.g. /var/www/html)").option("--php-version <version>", "PHP version", "8.2").option("--laravel-version <version>", "Laravel version", "10.x").option("--node-version <version>", "Node.js version", "20.x").option("--test-command <cmd>", "Test command", "php artisan test --compact").option("--cwd <path>", "Working directory", process.cwd()).option("--output <path>", "Output path (default: .github/agents/project-config.yml)").option("--force", "Overwrite existing file", false).action(async (opts) => {
|
|
1093
1104
|
const { access, mkdir } = await import("fs/promises");
|
|
1094
1105
|
const { dirname } = await import("path");
|
|
1095
1106
|
const outputPath = opts.output ? resolve2(opts.cwd, opts.output) : resolve2(opts.cwd, DEFAULT_CONFIG_PATH);
|
|
@@ -1105,11 +1116,14 @@ Use --force to overwrite.
|
|
|
1105
1116
|
} catch {
|
|
1106
1117
|
}
|
|
1107
1118
|
}
|
|
1119
|
+
const projectName = opts.projectName ?? await prompt("Project name", "My Laravel Project");
|
|
1120
|
+
const client = opts.client ?? await prompt("Client name", "Client Name");
|
|
1108
1121
|
const yaml = generateConfigYaml({
|
|
1109
|
-
projectName
|
|
1110
|
-
client
|
|
1122
|
+
projectName,
|
|
1123
|
+
client,
|
|
1111
1124
|
execution: opts.execution,
|
|
1112
1125
|
dockerService: opts.dockerService,
|
|
1126
|
+
dockerWorkdir: opts.dockerWorkdir,
|
|
1113
1127
|
phpVersion: opts.phpVersion,
|
|
1114
1128
|
laravelVersion: opts.laravelVersion,
|
|
1115
1129
|
nodeVersion: opts.nodeVersion,
|
|
@@ -1127,6 +1141,8 @@ Next steps:
|
|
|
1127
1141
|
process.stdout.write(` 2. Review protected_packages \u2014 add any packages that must not be auto-upgraded
|
|
1128
1142
|
`);
|
|
1129
1143
|
process.stdout.write(` 3. Run: osv-security scan --cwd <your-project-dir>
|
|
1144
|
+
`);
|
|
1145
|
+
process.stdout.write(` (config will be loaded from project-config.yml at project root by default)
|
|
1130
1146
|
`);
|
|
1131
1147
|
});
|
|
1132
1148
|
commonOptions(
|
|
@@ -1154,7 +1170,8 @@ async function runCommand(command, opts) {
|
|
|
1154
1170
|
config.runtime.execution,
|
|
1155
1171
|
config.runtime.docker_service,
|
|
1156
1172
|
opts.cwd,
|
|
1157
|
-
opts.dryRun
|
|
1173
|
+
opts.dryRun,
|
|
1174
|
+
config.runtime.docker_workdir
|
|
1158
1175
|
);
|
|
1159
1176
|
if (command === "scan") {
|
|
1160
1177
|
const scanResult = await runScanner(runner, config, opts.cwd);
|