@codacy/verity-cli 0.29.2 → 0.29.4
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/bin/verity.js +57 -8
- package/data/skills/verity-setup/SKILL.md +91 -2
- package/package.json +1 -1
package/bin/verity.js
CHANGED
|
@@ -10833,6 +10833,12 @@ function writeBaselineSha(sha) {
|
|
|
10833
10833
|
} catch {
|
|
10834
10834
|
}
|
|
10835
10835
|
}
|
|
10836
|
+
var VERITY_OWNED_PREFIXES = [".verity/", ".gate/", ".codacy/"];
|
|
10837
|
+
var VERITY_OWNED_FILES = ["VERITY.md"];
|
|
10838
|
+
function isVerityOwnedPath(file) {
|
|
10839
|
+
const p = file.replace(/\\/g, "/");
|
|
10840
|
+
return VERITY_OWNED_PREFIXES.some((d) => p.startsWith(d)) || VERITY_OWNED_FILES.includes(p);
|
|
10841
|
+
}
|
|
10836
10842
|
function getChangedFiles() {
|
|
10837
10843
|
const sets = /* @__PURE__ */ new Set();
|
|
10838
10844
|
let hasRecentCommitFiles = false;
|
|
@@ -10859,18 +10865,18 @@ function getChangedFiles() {
|
|
|
10859
10865
|
}
|
|
10860
10866
|
}
|
|
10861
10867
|
}
|
|
10862
|
-
const filtered = Array.from(sets).filter((f) => !
|
|
10868
|
+
const filtered = Array.from(sets).filter((f) => !isVerityOwnedPath(f));
|
|
10863
10869
|
return { files: filtered, hasRecentCommitFiles };
|
|
10864
10870
|
}
|
|
10865
10871
|
function getStagedFiles() {
|
|
10866
|
-
return splitLines(execGit("git diff --cached --name-only")).filter((f) => !
|
|
10872
|
+
return splitLines(execGit("git diff --cached --name-only")).filter((f) => !isVerityOwnedPath(f));
|
|
10867
10873
|
}
|
|
10868
10874
|
function getDirtyFiles() {
|
|
10869
10875
|
const set = /* @__PURE__ */ new Set();
|
|
10870
10876
|
for (const f of splitLines(execGit("git diff --name-only HEAD"))) set.add(f);
|
|
10871
10877
|
for (const f of splitLines(execGit("git diff --name-only --cached"))) set.add(f);
|
|
10872
10878
|
for (const f of splitLines(execGit("git ls-files --others --exclude-standard"))) set.add(f);
|
|
10873
|
-
return Array.from(set).filter((f) => !
|
|
10879
|
+
return Array.from(set).filter((f) => !isVerityOwnedPath(f));
|
|
10874
10880
|
}
|
|
10875
10881
|
function showContentAtRef(ref, repoRelPath) {
|
|
10876
10882
|
if (!ref || ref === "no-git") return null;
|
|
@@ -16809,6 +16815,46 @@ function interpretAnalyzerRun(run) {
|
|
|
16809
16815
|
};
|
|
16810
16816
|
}
|
|
16811
16817
|
|
|
16818
|
+
// src/lib/remediation-guard.ts
|
|
16819
|
+
var TOOL_CONFIG_PATTERNS = [
|
|
16820
|
+
/(^|\/)\.codacy\//,
|
|
16821
|
+
/(^|\/)codacy\.(config\.)?(json|ya?ml)$/,
|
|
16822
|
+
/(^|\/)eslint\.config\.(js|mjs|cjs|ts)$/,
|
|
16823
|
+
/(^|\/)\.eslintrc(\.(json|ya?ml|js|cjs))?$/,
|
|
16824
|
+
/(^|\/)\.?semgrep(\.(ya?ml))?$/,
|
|
16825
|
+
/(^|\/)trivy\.ya?ml$/,
|
|
16826
|
+
/(^|\/)\.trivyignore$/,
|
|
16827
|
+
/(^|\/)sonar-project\.properties$/,
|
|
16828
|
+
/(^|\/)\.?ruff\.toml$/,
|
|
16829
|
+
/(^|\/)\.bandit$/,
|
|
16830
|
+
/(^|\/)pmd\.xml$/,
|
|
16831
|
+
/(^|\/)\.hadolint\.ya?ml$/
|
|
16832
|
+
];
|
|
16833
|
+
function isAnalysisToolConfig(file) {
|
|
16834
|
+
if (!file) return false;
|
|
16835
|
+
const p = file.replace(/\\/g, "/");
|
|
16836
|
+
return TOOL_CONFIG_PATTERNS.some((re) => re.test(p));
|
|
16837
|
+
}
|
|
16838
|
+
var PROPOSES_PATTERN_ID = /["']patternId["']\s*:/;
|
|
16839
|
+
function screenRemediation(fix, findingFile) {
|
|
16840
|
+
const suggestion = typeof fix?.suggestion === "string" ? fix.suggestion : "";
|
|
16841
|
+
if (!suggestion) return { suggestion: null, withheldReason: null };
|
|
16842
|
+
const target = typeof fix?.file === "string" && fix.file || (typeof findingFile === "string" ? findingFile : "");
|
|
16843
|
+
if (isAnalysisToolConfig(target)) {
|
|
16844
|
+
return {
|
|
16845
|
+
suggestion: null,
|
|
16846
|
+
withheldReason: "withheld \u2014 Verity does not hand-write edits to analysis-tool configuration. Run `node .claude/skills/verity-setup/validate-patterns.mjs` to check this file against the real adapter catalogue."
|
|
16847
|
+
};
|
|
16848
|
+
}
|
|
16849
|
+
if (PROPOSES_PATTERN_ID.test(suggestion)) {
|
|
16850
|
+
return {
|
|
16851
|
+
suggestion: null,
|
|
16852
|
+
withheldReason: "withheld \u2014 this suggestion proposes a tool `patternId`, which Verity cannot verify. Check it with `node .claude/skills/verity-setup/validate-patterns.mjs --list <toolId>` before applying."
|
|
16853
|
+
};
|
|
16854
|
+
}
|
|
16855
|
+
return { suggestion, withheldReason: null };
|
|
16856
|
+
}
|
|
16857
|
+
|
|
16812
16858
|
// src/lib/specs.ts
|
|
16813
16859
|
var import_node_fs17 = require("node:fs");
|
|
16814
16860
|
var import_node_path16 = require("node:path");
|
|
@@ -16965,7 +17011,7 @@ function resolveTaskContext(opts) {
|
|
|
16965
17011
|
// src/lib/cli-version.ts
|
|
16966
17012
|
function cliVersion() {
|
|
16967
17013
|
try {
|
|
16968
|
-
return true ? "0.29.
|
|
17014
|
+
return true ? "0.29.4" : "dev";
|
|
16969
17015
|
} catch {
|
|
16970
17016
|
return "dev";
|
|
16971
17017
|
}
|
|
@@ -19661,15 +19707,18 @@ ${lines.join("\n")}`,
|
|
|
19661
19707
|
const line = f.line ?? "";
|
|
19662
19708
|
const fix = f.fix;
|
|
19663
19709
|
const fixDesc = fix?.description ?? "See description";
|
|
19664
|
-
const
|
|
19710
|
+
const screened = screenRemediation(fix, f.file);
|
|
19665
19711
|
process.stderr.write(`[${severity}] ${title}
|
|
19666
19712
|
`);
|
|
19667
19713
|
process.stderr.write(` File: ${file}:${line}
|
|
19668
19714
|
`);
|
|
19669
19715
|
process.stderr.write(` Fix: ${fixDesc}
|
|
19670
19716
|
`);
|
|
19671
|
-
if (suggestion) {
|
|
19672
|
-
process.stderr.write(` Suggestion: ${suggestion}
|
|
19717
|
+
if (screened.suggestion) {
|
|
19718
|
+
process.stderr.write(` Suggestion: ${screened.suggestion}
|
|
19719
|
+
`);
|
|
19720
|
+
} else if (screened.withheldReason) {
|
|
19721
|
+
process.stderr.write(` Suggestion: ${screened.withheldReason}
|
|
19673
19722
|
`);
|
|
19674
19723
|
}
|
|
19675
19724
|
process.stderr.write("\n");
|
|
@@ -21564,7 +21613,7 @@ function registerTelemetryCommands(program2) {
|
|
|
21564
21613
|
}
|
|
21565
21614
|
|
|
21566
21615
|
// src/cli.ts
|
|
21567
|
-
program.name("verity").description("CLI for Verity quality gate service").version("0.29.
|
|
21616
|
+
program.name("verity").description("CLI for Verity quality gate service").version("0.29.4").option("--token <token>", "Override authentication token").option("--service-url <url>", "Override service URL").option("--verbose", "Log HTTP requests/responses to stderr").hook("preAction", async () => {
|
|
21568
21617
|
setUserNamedServiceUrl(program.opts().serviceUrl);
|
|
21569
21618
|
try {
|
|
21570
21619
|
await foldLegacyLocalCredential();
|
|
@@ -221,7 +221,43 @@ it from the installed adapter. Then **always validate** (next section).
|
|
|
221
221
|
about signal rather than a complete enumeration. Copy the pattern list for each
|
|
222
222
|
tool selected for this mode. `--list <toolId> <regex>` will confirm any single ID
|
|
223
223
|
or let you derive additions.
|
|
224
|
-
|
|
224
|
+
> ⚠ **Semgrep ids carry a doubled suffix.** The rule name appears twice — once as
|
|
225
|
+
> the path segment and once as the rule id:
|
|
226
|
+
> `Semgrep_javascript.browser.security.raw-html-concat.raw-html-concat`. Deriving
|
|
227
|
+
> them with `--list Semgrep '<regex>'` gives the correct form; constructing them by
|
|
228
|
+
> hand from the rule name does not.
|
|
229
|
+
|
|
230
|
+
3. ⚠ **NEVER point `localConfigurationFile` at the project's own config** (VRT-108).
|
|
231
|
+
Doing so hands the tool the project's rule set, and Verity's `patterns` array
|
|
232
|
+
degrades to a **filter over rules someone else enabled** — it can no longer turn
|
|
233
|
+
a rule ON. A project that disables a rule makes it permanently unreachable by
|
|
234
|
+
the gate, silently. Measured: a repo whose `eslint.config.js` sets
|
|
235
|
+
`"@typescript-eslint/no-unused-vars": "off"` and omits `no-eval`/`eqeqeq`/`no-var`
|
|
236
|
+
had all four listed in its Verity config and **only** `no-explicit-any` could fire.
|
|
237
|
+
|
|
238
|
+
Setting the path is not even sufficient on its own. `useLocalConfigurationFile`
|
|
239
|
+
**defaults to true**, and the adapter auto-discovers `./eslint.config.js` and
|
|
240
|
+
overrides your value unless the flag is explicitly `false`:
|
|
241
|
+
|
|
242
|
+
```js
|
|
243
|
+
// @codacy/analysis-cli — defaults to true unless EXPLICITLY false
|
|
244
|
+
if (!existing || existing.useLocalConfigurationFile !== false) {
|
|
245
|
+
config.useLocalConfigurationFile = true;
|
|
246
|
+
}
|
|
247
|
+
// patterns become the ENABLED set only when the flag is false
|
|
248
|
+
if (!codacyToolConfig.useLocalConfigurationFile && codacyToolConfig.patterns.length === …)
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
So for ESLint9 always emit **both**:
|
|
252
|
+
|
|
253
|
+
- `"useLocalConfigurationFile": false` — makes `patterns` the enabled rule set
|
|
254
|
+
- `"localConfigurationFile": "./.codacy/tools-configs/eslint.config.mjs"` — a
|
|
255
|
+
**Verity-owned** config, written by this skill, so the gate does not inherit
|
|
256
|
+
the project's lint policy
|
|
257
|
+
|
|
258
|
+
The project's own `eslint.config.js` is left untouched and keeps serving
|
|
259
|
+
`npm run lint`. The two are deliberately independent: a team may reasonably turn
|
|
260
|
+
a rule off for their editor and still want the gate to enforce it.
|
|
225
261
|
4. For tools **without** a local config: populate the full curated pattern list from `patterns-reference.yaml`
|
|
226
262
|
5. **Validate** (next section). This is not optional — it is the only thing that
|
|
227
263
|
catches a stale or mistyped ID, and the failure mode is silent.
|
|
@@ -245,7 +281,8 @@ Delete `.codacy/codacy.config.json` and write a new one. This example is for Typ
|
|
|
245
281
|
"tools": [
|
|
246
282
|
{
|
|
247
283
|
"toolId": "ESLint9",
|
|
248
|
-
"localConfigurationFile": "
|
|
284
|
+
"localConfigurationFile": "./.codacy/tools-configs/eslint.config.mjs",
|
|
285
|
+
"useLocalConfigurationFile": false,
|
|
249
286
|
"patterns": [
|
|
250
287
|
{ "patternId": "ESLint9_no-eval" },
|
|
251
288
|
{ "patternId": "ESLint9_no-implied-eval" },
|
|
@@ -295,6 +332,58 @@ Delete `.codacy/codacy.config.json` and write a new one. This example is for Typ
|
|
|
295
332
|
}
|
|
296
333
|
```
|
|
297
334
|
|
|
335
|
+
### Also write the Verity-owned ESLint config
|
|
336
|
+
|
|
337
|
+
Because `useLocalConfigurationFile` is `false`, the adapter builds ESLint's rule set
|
|
338
|
+
from the `patterns` array — but ESLint still needs a config for parser, globals and
|
|
339
|
+
ignores. Write `.codacy/tools-configs/eslint.config.mjs`, adapted to the project's
|
|
340
|
+
frameworks and ignore paths:
|
|
341
|
+
|
|
342
|
+
```js
|
|
343
|
+
// Verity-owned ESLint config for the quality gate.
|
|
344
|
+
//
|
|
345
|
+
// Deliberately SEPARATE from the project's ./eslint.config.js. Pointing the gate at
|
|
346
|
+
// the project config makes Verity's pattern list a FILTER over rules the project
|
|
347
|
+
// enabled, so any rule the project disables becomes unreachable (VRT-108).
|
|
348
|
+
//
|
|
349
|
+
// Keep the rules here in sync with the ESLint9 patterns in codacy.config.json.
|
|
350
|
+
import js from "@eslint/js";
|
|
351
|
+
import globals from "globals";
|
|
352
|
+
import tseslint from "typescript-eslint";
|
|
353
|
+
|
|
354
|
+
export default tseslint.config(
|
|
355
|
+
{ ignores: ["dist/**", "build/**", "node_modules/**", "coverage/**", ".codacy/**"] },
|
|
356
|
+
{
|
|
357
|
+
extends: [js.configs.recommended, ...tseslint.configs.recommended],
|
|
358
|
+
files: ["**/*.{ts,tsx,js,jsx}"],
|
|
359
|
+
languageOptions: {
|
|
360
|
+
ecmaVersion: 2022,
|
|
361
|
+
sourceType: "module",
|
|
362
|
+
globals: { ...globals.browser, ...globals.node },
|
|
363
|
+
},
|
|
364
|
+
rules: {
|
|
365
|
+
// Mirror the ESLint9 patterns in codacy.config.json.
|
|
366
|
+
"no-eval": "error",
|
|
367
|
+
"no-implied-eval": "error",
|
|
368
|
+
"no-new-func": "error",
|
|
369
|
+
"no-script-url": "error",
|
|
370
|
+
eqeqeq: ["error", "smart"],
|
|
371
|
+
"no-var": "error",
|
|
372
|
+
"@typescript-eslint/no-explicit-any": "warn",
|
|
373
|
+
"@typescript-eslint/no-unused-vars": ["warn", { argsIgnorePattern: "^_" }],
|
|
374
|
+
},
|
|
375
|
+
},
|
|
376
|
+
);
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
⚠ **Do not enable type-checked rules** (`no-unsafe-assignment`, `no-unsafe-call`,
|
|
380
|
+
`no-unsafe-return`). They require `parserOptions.projectService`, which makes a
|
|
381
|
+
per-turn gate far too slow on a large repo. Cover those through AI review in the
|
|
382
|
+
Standard instead.
|
|
383
|
+
|
|
384
|
+
⚠ **Generated files belong in `ignores`** — `src/integrations/supabase/types.ts` and
|
|
385
|
+
similar. They are not the agent's work and will otherwise dominate the findings.
|
|
386
|
+
|
|
298
387
|
### Validate the config — REQUIRED, do not skip
|
|
299
388
|
|
|
300
389
|
Immediately after writing `.codacy/codacy.config.json`, run the validator that ships
|