@kinkai.cloud/vibecheck 0.3.0 → 0.3.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.
Files changed (3) hide show
  1. package/README.md +2 -2
  2. package/dist/cli.js +51 -14
  3. package/package.json +3 -3
package/README.md CHANGED
@@ -16,7 +16,7 @@ export PATH="$PWD/.tools/vibecheck/bin:$PATH"
16
16
  ```
17
17
 
18
18
  3. Gere seus relatórios com o runner de testes habitual. Configure os caminhos existentes em `coverage`, `junit` e `sarif` no JSON. Não adicione um relatório que seu projeto não gera. Formatos de cobertura: `lcov`, `cobertura`, `jacoco`.
19
- 4. Analise localmente: `npx vibecheck analyze`. Para publicar, configure `VIBECHECK_PROJECT_TOKEN` como variável de ambiente ou segredo do CI e execute `npx vibecheck analyze --publish`.
19
+ 4. Analise localmente: `npx vibecheck analyze`. Para publicar, configure `VIBECHECK_PROJECT_TOKEN` como variável de ambiente, em um arquivo `.env` na raiz do repositório, ou como segredo do CI, e execute `npx vibecheck analyze --publish`. O CLI carrega `.env` localmente quando a variável ainda não está definida no ambiente; nunca publica o arquivo.
20
20
 
21
21
  O CLI não roda testes arbitrários. Código-fonte completo e valores de segredos permanecem locais. Relatórios sanitizados ficam em `.vibecheck/analysis.json` e `.vibecheck/analysis.sarif`. Adicione `.tools/` e `.vibecheck/` ao `.gitignore`.
22
22
 
@@ -33,7 +33,7 @@ No painel: **Achados** para correções, **Mapa** para arquivos, **Dependências
33
33
  1. Create a project at https://vibecheck.kinkai.cloud/projects. Copy its configuration and generate a project token in Settings.
34
34
  2. Install the CLI and engines using the commands above on Linux x64 or WSL, with Python 3 and venv. Versions are pinned; OSV/Gitleaks binaries are checksum verified. npm does not install engines automatically.
35
35
  3. Generate reports using your usual test runner. Configure existing coverage (`lcov`, `cobertura`, `jacoco`), JUnit and SARIF paths. The CLI does not run arbitrary tests.
36
- 4. Run `npx vibecheck analyze`. To upload sanitized results, set `VIBECHECK_PROJECT_TOKEN` in your environment or CI secret store, then run `npx vibecheck analyze --publish`.
36
+ 4. Run `npx vibecheck analyze`. To upload sanitized results, set `VIBECHECK_PROJECT_TOKEN` in your environment, in a `.env` file at the repository root, or in your CI secret store, then run `npx vibecheck analyze --publish`. The CLI loads `.env` locally only when the variable is not already set; it never uploads that file.
37
37
 
38
38
  Publish the reference branch first. Without a comparable merge-base analysis, the gate is inconclusive. Exit codes: 0 pass, 1 fail, 2 inconclusive, 3 operational error. Default policy blocks new high/critical risks and secrets, and requires 80% coverage of new executable lines. Missing required evidence never means pass.
39
39
 
package/dist/cli.js CHANGED
@@ -6,7 +6,7 @@ var __export = (target, all2) => {
6
6
  };
7
7
 
8
8
  // src/analyze.ts
9
- import { mkdirSync as mkdirSync2, writeFileSync as writeFileSync2, existsSync, lstatSync as lstatSync2 } from "fs";
9
+ import { mkdirSync as mkdirSync2, writeFileSync as writeFileSync2, existsSync, lstatSync as lstatSync2, readFileSync as readFileSync3 } from "fs";
10
10
  import { resolve as resolve2, join as join3 } from "path";
11
11
 
12
12
  // ../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/external.js
@@ -17693,6 +17693,20 @@ var configSchema = external_exports.object({
17693
17693
  junit: external_exports.array(external_exports.string()).default([]),
17694
17694
  sarif: external_exports.array(external_exports.string()).default([])
17695
17695
  }).strict();
17696
+ function loadLocalEnv(root) {
17697
+ const file2 = join3(root, ".env");
17698
+ if (!existsSync(file2) || lstatSync2(file2).isSymbolicLink() || !lstatSync2(file2).isFile())
17699
+ return;
17700
+ for (const line of readFileSync3(file2, "utf8").split(/\r?\n/)) {
17701
+ const match = line.match(/^\s*(?:export\s+)?([A-Z_][A-Z0-9_]*)\s*=\s*(.*?)\s*$/);
17702
+ const key = match?.[1];
17703
+ if (!match || !key || process.env[key] !== void 0) continue;
17704
+ let value = match[2];
17705
+ if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'"))
17706
+ value = value.slice(1, -1);
17707
+ process.env[key] = value;
17708
+ }
17709
+ }
17696
17710
  async function analyzeCommand(argv) {
17697
17711
  if (argv.includes("--help")) {
17698
17712
  console.warn(
@@ -17705,14 +17719,37 @@ async function analyzeCommand(argv) {
17705
17719
  return i < 0 ? void 0 : argv[i + 1];
17706
17720
  };
17707
17721
  const root = resolve2(value("--dir") ?? process.cwd()), configPath = value("--config") ?? "vibecheck.config.json";
17708
- if (!existsSync(join3(root, configPath)))
17722
+ loadLocalEnv(root);
17723
+ const token = process.env["VIBECHECK_PROJECT_TOKEN"], base = process.env["VIBECHECK_URL"] ?? "https://vibecheck.kinkai.cloud";
17724
+ let config2;
17725
+ if (existsSync(join3(root, configPath))) {
17726
+ config2 = configSchema.parse(JSON.parse(localFile(root, configPath)));
17727
+ } else if (argv.includes("--publish") && token) {
17728
+ const response = await fetch(new URL("/api/projects", base), {
17729
+ headers: { authorization: "Bearer " + token },
17730
+ signal: AbortSignal.timeout(3e4)
17731
+ });
17732
+ if (!response.ok) throw new Error("Project token rejected while discovering project");
17733
+ const project = external_exports.object({ id: external_exports.string().uuid(), reference: external_exports.string() }).parse(await response.json());
17734
+ config2 = {
17735
+ version: 2,
17736
+ projectId: project.id,
17737
+ reference: project.reference,
17738
+ baseline: void 0,
17739
+ coverage: [],
17740
+ junit: [],
17741
+ sarif: []
17742
+ };
17743
+ console.warn(
17744
+ "No vibecheck.config.json found; using project settings discovered from the token."
17745
+ );
17746
+ } else {
17709
17747
  throw new Error(
17710
- "Create vibecheck.config.json with version: 2 and projectId from the web project."
17748
+ "Create vibecheck.config.json, or set VIBECHECK_PROJECT_TOKEN and use --publish to discover the project automatically."
17711
17749
  );
17712
- const config2 = configSchema.parse(JSON.parse(localFile(root, configPath)));
17750
+ }
17713
17751
  let baseline = config2.baseline ? analysisReportSchema.parse(JSON.parse(localFile(root, config2.baseline))) : null;
17714
17752
  let report = await analyze({ root, ...config2, baseline });
17715
- const token = process.env["VIBECHECK_PROJECT_TOKEN"], base = process.env["VIBECHECK_URL"] ?? "https://vibecheck.kinkai.cloud";
17716
17753
  const url2 = new URL(base);
17717
17754
  if (url2.protocol !== "https:" && !["localhost", "127.0.0.1"].includes(url2.hostname))
17718
17755
  throw new Error("Use HTTPS for project uploads");
@@ -18644,12 +18681,12 @@ var sequencedScanEventSchema = external_exports.intersection(
18644
18681
  );
18645
18682
 
18646
18683
  // src/consent.ts
18647
- import { chmodSync as chmodSync2, mkdirSync as mkdirSync4, readFileSync as readFileSync4, writeFileSync as writeFileSync4 } from "fs";
18684
+ import { chmodSync as chmodSync2, mkdirSync as mkdirSync4, readFileSync as readFileSync5, writeFileSync as writeFileSync4 } from "fs";
18648
18685
  import { createInterface } from "readline/promises";
18649
18686
  import { join as join5, resolve as resolve3 } from "path";
18650
18687
 
18651
18688
  // src/token.ts
18652
- import { chmodSync, mkdirSync as mkdirSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "fs";
18689
+ import { chmodSync, mkdirSync as mkdirSync3, readFileSync as readFileSync4, writeFileSync as writeFileSync3 } from "fs";
18653
18690
  import { homedir } from "os";
18654
18691
  import { join as join4 } from "path";
18655
18692
  function dirConfig() {
@@ -18665,7 +18702,7 @@ function lerToken() {
18665
18702
  return { token: env, host: hostEnv ?? "" };
18666
18703
  }
18667
18704
  try {
18668
- const bruto = readFileSync3(caminhoToken(), "utf8").trim();
18705
+ const bruto = readFileSync4(caminhoToken(), "utf8").trim();
18669
18706
  const [token, host] = bruto.split("\n");
18670
18707
  if (token === void 0 || token.length === 0) return null;
18671
18708
  return { token, host: host ?? "" };
@@ -18694,7 +18731,7 @@ function repoKey(dir) {
18694
18731
  }
18695
18732
  function listarConsentimentos(deps = {}) {
18696
18733
  try {
18697
- const bruto = JSON.parse(readFileSync4(caminho(deps), "utf8"));
18734
+ const bruto = JSON.parse(readFileSync5(caminho(deps), "utf8"));
18698
18735
  if (!Array.isArray(bruto)) return [];
18699
18736
  return bruto.filter(
18700
18737
  (e) => e !== null && typeof e === "object" && typeof e.repo === "string" && typeof e.acceptedAt === "string"
@@ -19077,7 +19114,7 @@ async function loginDevice(ci, options = {}) {
19077
19114
 
19078
19115
  // src/repo.ts
19079
19116
  import { execFileSync } from "child_process";
19080
- import { lstatSync as lstatSync3, readdirSync as readdirSync2, readFileSync as readFileSync5 } from "fs";
19117
+ import { lstatSync as lstatSync3, readdirSync as readdirSync2, readFileSync as readFileSync6 } from "fs";
19081
19118
  import { join as join8, relative as relative2 } from "path";
19082
19119
  var MAX_FILES = 800;
19083
19120
  var MAX_BYTES2 = 64e3;
@@ -19140,7 +19177,7 @@ function readCodeContext(dir) {
19140
19177
  try {
19141
19178
  const st = lstatSync3(join8(dir, path));
19142
19179
  if (st.size > (path.endsWith(".sql") ? MAX_SQL_BYTES : MAX_BYTES2)) continue;
19143
- files.push({ path, content: readFileSync5(join8(dir, path), "utf8") });
19180
+ files.push({ path, content: readFileSync6(join8(dir, path), "utf8") });
19144
19181
  } catch {
19145
19182
  }
19146
19183
  }
@@ -19194,7 +19231,7 @@ function toSarif(report, version2) {
19194
19231
  }
19195
19232
 
19196
19233
  // src/walker.ts
19197
- import { lstatSync as lstatSync4, readdirSync as readdirSync3, readFileSync as readFileSync6 } from "fs";
19234
+ import { lstatSync as lstatSync4, readdirSync as readdirSync3, readFileSync as readFileSync7 } from "fs";
19198
19235
  import { join as join9, relative as relative3 } from "path";
19199
19236
  var IGNORAR = /* @__PURE__ */ new Set([
19200
19237
  "node_modules",
@@ -19339,7 +19376,7 @@ function lerArquivo(raiz, cheio) {
19339
19376
  const rel = posixRel(raiz, cheio);
19340
19377
  let conteudo = "";
19341
19378
  try {
19342
- conteudo = readFileSync6(cheio, "utf8").slice(0, MAX_BYTES_ARQUIVO);
19379
+ conteudo = readFileSync7(cheio, "utf8").slice(0, MAX_BYTES_ARQUIVO);
19343
19380
  } catch {
19344
19381
  return null;
19345
19382
  }
@@ -19461,7 +19498,7 @@ function isAdvancedScan(grafo) {
19461
19498
  }
19462
19499
 
19463
19500
  // src/cli.ts
19464
- var VERSION = "0.3.0";
19501
+ var VERSION = "0.3.1";
19465
19502
  var AJUDA = `vibecheck \u2014 security check for AI-built apps
19466
19503
 
19467
19504
  npx @kinkai.cloud/vibecheck [options]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kinkai.cloud/vibecheck",
3
- "version": "0.3.0",
3
+ "version": "0.3.1",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "bin": {
@@ -25,8 +25,8 @@
25
25
  "zod": "^4",
26
26
  "@vibecheck/checks": "0.0.0",
27
27
  "@vibecheck/graph": "0.0.0",
28
- "@vibecheck/schema": "0.0.0",
29
- "@vibecheck/analysis": "0.0.0"
28
+ "@vibecheck/analysis": "0.0.0",
29
+ "@vibecheck/schema": "0.0.0"
30
30
  },
31
31
  "exports": {
32
32
  "./login": "./src/login.ts",