hex-audit 0.4.4 → 0.4.5
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/DEMO.md +3 -2
- package/README.md +45 -41
- package/dashboard/.next/BUILD_ID +1 -1
- package/dashboard/.next/app-build-manifest.json +18 -11
- package/dashboard/.next/app-path-routes-manifest.json +1 -1
- package/dashboard/.next/build-manifest.json +4 -4
- package/dashboard/.next/next-server.js.nft.json +1 -1
- package/dashboard/.next/prerender-manifest.js +1 -1
- package/dashboard/.next/prerender-manifest.json +1 -1
- package/dashboard/.next/required-server-files.json +1 -1
- package/dashboard/.next/routes-manifest.json +1 -1
- package/dashboard/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/dashboard/.next/server/app/_not-found.html +1 -1
- package/dashboard/.next/server/app/_not-found.rsc +4 -4
- package/dashboard/.next/server/app/access/page_client-reference-manifest.js +1 -1
- package/dashboard/.next/server/app/api/flows/route.js +1 -1
- package/dashboard/.next/server/app/api/issues/[id]/move/route.js +1 -1
- package/dashboard/.next/server/app/api/issues/[id]/route.js +1 -1
- package/dashboard/.next/server/app/calls/page_client-reference-manifest.js +1 -1
- package/dashboard/.next/server/app/conformance/page_client-reference-manifest.js +1 -1
- package/dashboard/.next/server/app/diagram/page_client-reference-manifest.js +1 -1
- package/dashboard/.next/server/app/diagram.html +1 -1
- package/dashboard/.next/server/app/diagram.rsc +4 -4
- package/dashboard/.next/server/app/flows/page_client-reference-manifest.js +1 -1
- package/dashboard/.next/server/app/flows.html +1 -1
- package/dashboard/.next/server/app/flows.rsc +4 -4
- package/dashboard/.next/server/app/functions/page_client-reference-manifest.js +1 -1
- package/dashboard/.next/server/app/issues/page.js +12 -1
- package/dashboard/.next/server/app/issues/page_client-reference-manifest.js +1 -1
- package/dashboard/.next/server/app/overleaf/page.js +1 -0
- package/dashboard/.next/server/app/overleaf/page.js.nft.json +1 -0
- package/dashboard/.next/server/app/overleaf/page_client-reference-manifest.js +1 -0
- package/dashboard/.next/server/app/page_client-reference-manifest.js +1 -1
- package/dashboard/.next/server/app/progress/page_client-reference-manifest.js +1 -1
- package/dashboard/.next/server/app/stats/page_client-reference-manifest.js +1 -1
- package/dashboard/.next/server/app-paths-manifest.json +8 -7
- package/dashboard/.next/server/chunks/431.js +1 -1
- package/dashboard/.next/server/functions-config-manifest.json +1 -1
- package/dashboard/.next/server/middleware-build-manifest.js +1 -1
- package/dashboard/.next/server/pages/404.html +1 -1
- package/dashboard/.next/server/pages/500.html +1 -1
- package/dashboard/.next/server/server-reference-manifest.js +1 -1
- package/dashboard/.next/server/server-reference-manifest.json +1 -1
- package/dashboard/.next/static/chunks/app/issues/page-30f7bcde0f4f6ddb.js +1 -0
- package/dashboard/.next/static/chunks/app/{layout-527d8aa86e483fbd.js → layout-cde7d75ea6df4f81.js} +1 -1
- package/dashboard/.next/static/chunks/app/overleaf/page-bcea12a80c97b92f.js +1 -0
- package/dashboard/.next/static/chunks/{main-70c6d841ad572657.js → main-8f1e837090aef5cf.js} +1 -1
- package/dashboard/.next/static/css/36c6bb859d4545fd.css +3 -0
- package/dashboard/app/api/flows/route.ts +4 -0
- package/dashboard/app/api/issues/[id]/move/route.ts +29 -58
- package/dashboard/app/api/issues/[id]/route.ts +11 -102
- package/dashboard/app/issues/IssuesBoardClient.tsx +109 -35
- package/dashboard/app/issues/page.tsx +37 -3
- package/dashboard/app/overleaf/OverleafClient.tsx +97 -0
- package/dashboard/app/overleaf/page.tsx +32 -0
- package/dashboard/components/DashboardLayout.tsx +8 -2
- package/dashboard/lib/finding-markdown.ts +59 -0
- package/dashboard/next.config.mjs +4 -0
- package/dist/analysis/external-calls.d.ts +8 -1
- package/dist/analysis/external-calls.d.ts.map +1 -1
- package/dist/analysis/external-calls.js +57 -13
- package/dist/analysis/external-calls.js.map +1 -1
- package/dist/commands/calls.d.ts.map +1 -1
- package/dist/commands/calls.js +15 -6
- package/dist/commands/calls.js.map +1 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +17 -19
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/issue.d.ts +3 -0
- package/dist/commands/issue.d.ts.map +1 -0
- package/dist/commands/issue.js +115 -0
- package/dist/commands/issue.js.map +1 -0
- package/dist/core/issues.d.ts +79 -0
- package/dist/core/issues.d.ts.map +1 -0
- package/dist/core/issues.js +253 -0
- package/dist/core/issues.js.map +1 -0
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/skills/init-audit.md +3 -1
- package/dist/skills/sync-issues.md +17 -34
- package/dist/skills/validate-issue.md +20 -10
- package/dist/skills/write-finding.md +1 -1
- package/package.json +1 -1
- package/dashboard/.next/server/app/api/flows.body +0 -1
- package/dashboard/.next/server/app/api/flows.meta +0 -1
- package/dashboard/.next/static/chunks/app/issues/page-dc110d4cc0a5c398.js +0 -1
- package/dashboard/.next/static/css/7a38e5062ba6d403.css +0 -3
- /package/dashboard/.next/static/{ePObaFrrwft0BlvlllUMo → 4HWoeGmBSZi6iGcKL3VWA}/_buildManifest.js +0 -0
- /package/dashboard/.next/static/{ePObaFrrwft0BlvlllUMo → 4HWoeGmBSZi6iGcKL3VWA}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { logger } from '../core/logger.js';
|
|
5
|
+
import { loadConfig } from '../core/config.js';
|
|
6
|
+
import { getOutputDir } from '../core/paths.js';
|
|
7
|
+
import { reportError } from '../core/errors.js';
|
|
8
|
+
import { moveIssue, patchIssue, COLUMN_TO_STATUS } from '../core/issues.js';
|
|
9
|
+
function resolveOutputDir(opts) {
|
|
10
|
+
const projectDir = path.resolve(opts.project ?? process.cwd());
|
|
11
|
+
const config = loadConfig(projectDir);
|
|
12
|
+
return getOutputDir(config.project.project_dir, config.settings.output_dir);
|
|
13
|
+
}
|
|
14
|
+
const moveCmd = new Command('move')
|
|
15
|
+
.description('Move an issue between board columns (potential | verified | invalid | duplicate)')
|
|
16
|
+
.argument('<id>', 'Issue id (e.g. F001, SC-001, AA-003, github-12)')
|
|
17
|
+
.requiredOption('--to <column>', 'Target column: potential | verified | invalid | duplicate')
|
|
18
|
+
.option('--project <dir>', 'Project directory')
|
|
19
|
+
.action((id, opts) => {
|
|
20
|
+
try {
|
|
21
|
+
const column = opts.to;
|
|
22
|
+
if (!(column in COLUMN_TO_STATUS)) {
|
|
23
|
+
logger.error(`Invalid --to: ${opts.to}. Use one of: ${Object.keys(COLUMN_TO_STATUS).join(', ')}`);
|
|
24
|
+
process.exit(1);
|
|
25
|
+
}
|
|
26
|
+
const outputDir = resolveOutputDir(opts);
|
|
27
|
+
const entry = moveIssue(outputDir, id, column);
|
|
28
|
+
logger.success(`${id} → ${column} (status: ${entry.status})`);
|
|
29
|
+
}
|
|
30
|
+
catch (err) {
|
|
31
|
+
reportError(err);
|
|
32
|
+
process.exit(1);
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
const patchCmd = new Command('patch')
|
|
36
|
+
.description('Edit fields on an issue (materializes a findings.json entry if needed)')
|
|
37
|
+
.argument('<id>', 'Issue id')
|
|
38
|
+
.option('--title <title>', 'New title')
|
|
39
|
+
.option('--severity <severity>', 'Critical | High | Medium | Low | Info')
|
|
40
|
+
.option('--resolution <resolution>', 'Fixed | Mitigated | Acknowledged | Not Fixed | Unresolved')
|
|
41
|
+
.option('--description-file <path>', 'Read the description from this file')
|
|
42
|
+
.option('--recommendation-file <path>', 'Read the recommendation from this file')
|
|
43
|
+
.option('--update-from-client <text>', 'Client update text')
|
|
44
|
+
.option('--notes <text>', 'Tracking notes')
|
|
45
|
+
.option('--project <dir>', 'Project directory')
|
|
46
|
+
.action((id, opts) => {
|
|
47
|
+
try {
|
|
48
|
+
const updates = {};
|
|
49
|
+
if (opts.title != null)
|
|
50
|
+
updates.title = opts.title;
|
|
51
|
+
if (opts.severity != null)
|
|
52
|
+
updates.severity = opts.severity;
|
|
53
|
+
if (opts.resolution != null)
|
|
54
|
+
updates.resolution = opts.resolution;
|
|
55
|
+
if (opts.updateFromClient != null)
|
|
56
|
+
updates.update_from_client = opts.updateFromClient;
|
|
57
|
+
if (opts.notes != null)
|
|
58
|
+
updates.notes = opts.notes;
|
|
59
|
+
if (opts.descriptionFile != null) {
|
|
60
|
+
updates.description = fs.readFileSync(path.resolve(opts.descriptionFile), 'utf-8').trim();
|
|
61
|
+
}
|
|
62
|
+
if (opts.recommendationFile != null) {
|
|
63
|
+
updates.recommendation = fs
|
|
64
|
+
.readFileSync(path.resolve(opts.recommendationFile), 'utf-8')
|
|
65
|
+
.trim();
|
|
66
|
+
}
|
|
67
|
+
if (Object.keys(updates).length === 0) {
|
|
68
|
+
logger.error('Nothing to patch. Pass at least one of --title/--severity/--resolution/--description-file/--recommendation-file/--update-from-client/--notes.');
|
|
69
|
+
process.exit(1);
|
|
70
|
+
}
|
|
71
|
+
const outputDir = resolveOutputDir(opts);
|
|
72
|
+
const updated = patchIssue(outputDir, id, updates);
|
|
73
|
+
logger.success(`Patched ${id} (${Object.keys(updates).join(', ')})`);
|
|
74
|
+
logger.dim(`severity=${updated.severity} resolution=${updated.resolution ?? '(none)'}`);
|
|
75
|
+
}
|
|
76
|
+
catch (err) {
|
|
77
|
+
reportError(err);
|
|
78
|
+
process.exit(1);
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
const showCmd = new Command('show')
|
|
82
|
+
.description('Print the merged finding + tracking record for an issue id')
|
|
83
|
+
.argument('<id>', 'Issue id')
|
|
84
|
+
.option('--project <dir>', 'Project directory')
|
|
85
|
+
.action((id, opts) => {
|
|
86
|
+
try {
|
|
87
|
+
const outputDir = resolveOutputDir(opts);
|
|
88
|
+
const findings = JSON.parse(fs.readFileSync(path.join(outputDir, 'findings.json'), 'utf-8'));
|
|
89
|
+
const tracking = (() => {
|
|
90
|
+
try {
|
|
91
|
+
return JSON.parse(fs.readFileSync(path.join(outputDir, 'tracking.json'), 'utf-8'));
|
|
92
|
+
}
|
|
93
|
+
catch {
|
|
94
|
+
return { findings: [] };
|
|
95
|
+
}
|
|
96
|
+
})();
|
|
97
|
+
const finding = findings.findings.find((f) => f.id === id) ?? null;
|
|
98
|
+
const track = tracking.findings.find((t) => t.id === id) ?? null;
|
|
99
|
+
if (!finding && !track) {
|
|
100
|
+
logger.error(`No issue with id ${id} in findings.json or tracking.json`);
|
|
101
|
+
process.exit(1);
|
|
102
|
+
}
|
|
103
|
+
console.log(JSON.stringify({ id, finding, tracking: track }, null, 2));
|
|
104
|
+
}
|
|
105
|
+
catch (err) {
|
|
106
|
+
reportError(err);
|
|
107
|
+
process.exit(1);
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
export const issueCommand = new Command('issue')
|
|
111
|
+
.description('Inspect and mutate issues on the board (move / patch / show)')
|
|
112
|
+
.addCommand(moveCmd)
|
|
113
|
+
.addCommand(patchCmd)
|
|
114
|
+
.addCommand(showCmd);
|
|
115
|
+
//# sourceMappingURL=issue.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"issue.js","sourceRoot":"","sources":["../../src/commands/issue.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
export type BoardColumn = 'potential' | 'verified' | 'invalid' | 'duplicate';
|
|
2
|
+
export type Severity = 'Critical' | 'High' | 'Medium' | 'Low' | 'Info';
|
|
3
|
+
export type Resolution = 'Fixed' | 'Mitigated' | 'Acknowledged' | 'Not Fixed' | 'Unresolved';
|
|
4
|
+
export declare const SEVERITY_VALUES: readonly Severity[];
|
|
5
|
+
export declare const RESOLUTION_VALUES: readonly Resolution[];
|
|
6
|
+
export declare const COLUMN_TO_STATUS: Record<BoardColumn, string>;
|
|
7
|
+
/** Fields a user may edit through the board modal or `hex issue patch`. */
|
|
8
|
+
export declare const EDITABLE_FIELDS: readonly ["title", "severity", "description", "recommendation", "resolution", "update_from_client", "notes"];
|
|
9
|
+
export type EditableField = (typeof EDITABLE_FIELDS)[number];
|
|
10
|
+
interface FindingLocation {
|
|
11
|
+
file: string;
|
|
12
|
+
snippet?: string;
|
|
13
|
+
}
|
|
14
|
+
export interface Finding {
|
|
15
|
+
id: string;
|
|
16
|
+
title: string;
|
|
17
|
+
severity: Severity;
|
|
18
|
+
category: string;
|
|
19
|
+
description: string;
|
|
20
|
+
root_cause: {
|
|
21
|
+
locations: FindingLocation[];
|
|
22
|
+
};
|
|
23
|
+
poc: {
|
|
24
|
+
status: string;
|
|
25
|
+
file: string | null;
|
|
26
|
+
validation_memo: string | null;
|
|
27
|
+
};
|
|
28
|
+
recommendation: string;
|
|
29
|
+
references: {
|
|
30
|
+
external_links: string[];
|
|
31
|
+
};
|
|
32
|
+
created_at: string;
|
|
33
|
+
update_from_client?: string;
|
|
34
|
+
resolution?: Resolution;
|
|
35
|
+
github?: Record<string, unknown>;
|
|
36
|
+
[k: string]: unknown;
|
|
37
|
+
}
|
|
38
|
+
export interface TrackingEntry {
|
|
39
|
+
id: string;
|
|
40
|
+
title: string;
|
|
41
|
+
severity: Severity;
|
|
42
|
+
source: string;
|
|
43
|
+
status: string;
|
|
44
|
+
poc_status: string;
|
|
45
|
+
poc_file: string | null;
|
|
46
|
+
duplicates: string[];
|
|
47
|
+
duplicate_of?: string | null;
|
|
48
|
+
notes: string;
|
|
49
|
+
[k: string]: unknown;
|
|
50
|
+
}
|
|
51
|
+
export declare function isValidSeverity(v: unknown): v is Severity;
|
|
52
|
+
export declare function isValidResolution(v: unknown): v is Resolution;
|
|
53
|
+
/**
|
|
54
|
+
* Ensure a findings.json entry exists for `id`, materializing one from the
|
|
55
|
+
* source-specific record if needed. Idempotent: returns the existing entry
|
|
56
|
+
* untouched when present. Dispatches on id prefix.
|
|
57
|
+
*/
|
|
58
|
+
export declare function ensureFindingExists(outputDir: string, id: string): Finding;
|
|
59
|
+
/**
|
|
60
|
+
* Move an issue between board columns. Materializes a findings.json entry first
|
|
61
|
+
* (so non-manual cards become reportable when promoted to Verified), then flips
|
|
62
|
+
* the tracking status.
|
|
63
|
+
*
|
|
64
|
+
* Note: this does NOT edit the user's source files. Source annotation
|
|
65
|
+
* (`// @audit-issue-verified ...`) remains the responsibility of the
|
|
66
|
+
* /validate-issue skill, which the auditor invokes deliberately — a drag-drop
|
|
67
|
+
* on the board should never silently rewrite .sol files.
|
|
68
|
+
*/
|
|
69
|
+
export declare function moveIssue(outputDir: string, id: string, column: BoardColumn): TrackingEntry;
|
|
70
|
+
/**
|
|
71
|
+
* Patch editable fields on an issue. Materializes a findings.json entry first so
|
|
72
|
+
* description / recommendation / resolution / update_from_client always land on
|
|
73
|
+
* a real record (not just non-manual cards' tracking rows). Title / severity /
|
|
74
|
+
* notes are mirrored on the tracking entry so the board reads current values
|
|
75
|
+
* without re-reading findings.json.
|
|
76
|
+
*/
|
|
77
|
+
export declare function patchIssue(outputDir: string, id: string, updates: Record<string, unknown>): Finding;
|
|
78
|
+
export {};
|
|
79
|
+
//# sourceMappingURL=issues.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"issues.d.ts","sourceRoot":"","sources":["../../src/core/issues.ts"],"names":[],"mappings":"AAmBA,MAAM,MAAM,WAAW,GAAG,WAAW,GAAG,UAAU,GAAG,SAAS,GAAG,WAAW,CAAC;AAC7E,MAAM,MAAM,QAAQ,GAAG,UAAU,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,GAAG,MAAM,CAAC;AACvE,MAAM,MAAM,UAAU,GAAG,OAAO,GAAG,WAAW,GAAG,cAAc,GAAG,WAAW,GAAG,YAAY,CAAC;AAE7F,eAAO,MAAM,eAAe,EAAE,SAAS,QAAQ,EAAkD,CAAC;AAClG,eAAO,MAAM,iBAAiB,EAAE,SAAS,UAAU,EAMlD,CAAC;AAEF,eAAO,MAAM,gBAAgB,EAAE,MAAM,CAAC,WAAW,EAAE,MAAM,CAKxD,CAAC;AAEF,2EAA2E;AAC3E,eAAO,MAAM,eAAe,8GAQlB,CAAC;AACX,MAAM,MAAM,aAAa,GAAG,CAAC,OAAO,eAAe,CAAC,CAAC,MAAM,CAAC,CAAC;AAE7D,UAAU,eAAe;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,QAAQ,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE;QAAE,SAAS,EAAE,eAAe,EAAE,CAAA;KAAE,CAAC;IAC7C,GAAG,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,eAAe,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC;IAC7E,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE;QAAE,cAAc,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;IACzC,UAAU,EAAE,MAAM,CAAC;IACnB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,QAAQ,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB;AAoCD,wBAAgB,eAAe,CAAC,CAAC,EAAE,OAAO,GAAG,CAAC,IAAI,QAAQ,CAEzD;AACD,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,OAAO,GAAG,CAAC,IAAI,UAAU,CAE7D;AAmED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CA2B1E;AAID;;;;;;;;;GASG;AACH,wBAAgB,SAAS,CAAC,SAAS,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,aAAa,CAmC3F;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CACxB,SAAS,EAAE,MAAM,EACjB,EAAE,EAAE,MAAM,EACV,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC/B,OAAO,CA0CT"}
|
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical issue-mutation logic, shared by the `hex issue` CLI command and the
|
|
3
|
+
* dashboard's PATCH/move API routes. Pure: depends only on node:fs / node:path
|
|
4
|
+
* and is parameterized by `outputDir` (the project's `.hex/` directory) so it
|
|
5
|
+
* can run from the CLI (resolves outputDir via config) or from the dashboard
|
|
6
|
+
* server runtime (resolves outputDir via process.cwd()).
|
|
7
|
+
*
|
|
8
|
+
* The single source of truth for: materializing a findings.json entry from a
|
|
9
|
+
* source-specific record (conformance / auditagent / github), routing edits
|
|
10
|
+
* between findings.json and tracking.json, and column→status mapping.
|
|
11
|
+
*
|
|
12
|
+
* Deliberately NOT imported across the src/ <-> dashboard/ tree boundary as a
|
|
13
|
+
* dependency chain: it pulls in nothing beyond node builtins, so the dashboard
|
|
14
|
+
* can import it via `experimental.externalDir` without dragging CLI deps
|
|
15
|
+
* (chalk/ora/zod) into the Next.js bundle.
|
|
16
|
+
*/
|
|
17
|
+
import fs from 'node:fs';
|
|
18
|
+
import path from 'node:path';
|
|
19
|
+
export const SEVERITY_VALUES = ['Critical', 'High', 'Medium', 'Low', 'Info'];
|
|
20
|
+
export const RESOLUTION_VALUES = [
|
|
21
|
+
'Fixed',
|
|
22
|
+
'Mitigated',
|
|
23
|
+
'Acknowledged',
|
|
24
|
+
'Not Fixed',
|
|
25
|
+
'Unresolved',
|
|
26
|
+
];
|
|
27
|
+
export const COLUMN_TO_STATUS = {
|
|
28
|
+
potential: 'pending_validation',
|
|
29
|
+
verified: 'verified',
|
|
30
|
+
invalid: 'rejected',
|
|
31
|
+
duplicate: 'duplicate',
|
|
32
|
+
};
|
|
33
|
+
/** Fields a user may edit through the board modal or `hex issue patch`. */
|
|
34
|
+
export const EDITABLE_FIELDS = [
|
|
35
|
+
'title',
|
|
36
|
+
'severity',
|
|
37
|
+
'description',
|
|
38
|
+
'recommendation',
|
|
39
|
+
'resolution',
|
|
40
|
+
'update_from_client',
|
|
41
|
+
'notes',
|
|
42
|
+
];
|
|
43
|
+
// ─── Low-level IO (atomic, JSON) ────────────────────────────────────
|
|
44
|
+
function readJson(file) {
|
|
45
|
+
try {
|
|
46
|
+
return JSON.parse(fs.readFileSync(file, 'utf-8'));
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
function writeJson(file, data) {
|
|
53
|
+
const dir = path.dirname(file);
|
|
54
|
+
if (!fs.existsSync(dir))
|
|
55
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
56
|
+
const tmp = file + '.tmp';
|
|
57
|
+
fs.writeFileSync(tmp, JSON.stringify(data, null, 2) + '\n', 'utf-8');
|
|
58
|
+
fs.renameSync(tmp, file);
|
|
59
|
+
}
|
|
60
|
+
function loadFindings(outputDir) {
|
|
61
|
+
return readJson(path.join(outputDir, 'findings.json')) ?? { findings: [] };
|
|
62
|
+
}
|
|
63
|
+
function loadTracking(outputDir) {
|
|
64
|
+
return readJson(path.join(outputDir, 'tracking.json')) ?? { findings: [] };
|
|
65
|
+
}
|
|
66
|
+
// ─── Validation ─────────────────────────────────────────────────────
|
|
67
|
+
export function isValidSeverity(v) {
|
|
68
|
+
return typeof v === 'string' && SEVERITY_VALUES.includes(v);
|
|
69
|
+
}
|
|
70
|
+
export function isValidResolution(v) {
|
|
71
|
+
return typeof v === 'string' && RESOLUTION_VALUES.includes(v);
|
|
72
|
+
}
|
|
73
|
+
// ─── Source-specific materialization ────────────────────────────────
|
|
74
|
+
function newEmptyFinding(id, severity) {
|
|
75
|
+
return {
|
|
76
|
+
id,
|
|
77
|
+
title: id,
|
|
78
|
+
severity,
|
|
79
|
+
category: '',
|
|
80
|
+
description: '',
|
|
81
|
+
root_cause: { locations: [] },
|
|
82
|
+
poc: { status: 'not_started', file: null, validation_memo: null },
|
|
83
|
+
recommendation: '',
|
|
84
|
+
references: { external_links: [] },
|
|
85
|
+
created_at: new Date().toISOString(),
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
/** Build a findings.json record from a conformance item (`SC-*`). */
|
|
89
|
+
function findingFromConformance(outputDir, id, tracking) {
|
|
90
|
+
const spec = readJson(path.join(outputDir, 'spec-conformance.json'));
|
|
91
|
+
const item = spec?.items?.find((i) => i.id === id);
|
|
92
|
+
if (!item)
|
|
93
|
+
return null;
|
|
94
|
+
const f = newEmptyFinding(id, (tracking?.severity ?? item.severity_hint ?? 'Info'));
|
|
95
|
+
f.title = tracking?.title ?? String(item.spec_text ?? id);
|
|
96
|
+
f.category = 'Spec Conformance';
|
|
97
|
+
f.description = String(item.finding ?? item.spec_text ?? '');
|
|
98
|
+
const loc = item.code_location;
|
|
99
|
+
if (loc?.file)
|
|
100
|
+
f.root_cause.locations = [{ file: loc.file }];
|
|
101
|
+
f.notes = `Materialized from conformance item ${id}`;
|
|
102
|
+
return f;
|
|
103
|
+
}
|
|
104
|
+
/** Build a findings.json record from an ai-results or external/github record. */
|
|
105
|
+
function findingFromAiOrGithub(outputDir, id, kind, tracking) {
|
|
106
|
+
const nested = kind === 'auditagent'
|
|
107
|
+
? path.join(outputDir, 'ai-results', 'auditagent', 'findings.json')
|
|
108
|
+
: path.join(outputDir, 'external', 'github', 'findings.json');
|
|
109
|
+
const file = readJson(nested);
|
|
110
|
+
const rec = file?.findings?.find((r) => r.id === id);
|
|
111
|
+
if (!rec)
|
|
112
|
+
return null;
|
|
113
|
+
const f = newEmptyFinding(id, rec.severity ?? tracking?.severity ?? 'Info');
|
|
114
|
+
f.title = String(rec.title ?? tracking?.title ?? id);
|
|
115
|
+
f.category = String(rec.category ?? '');
|
|
116
|
+
f.description = String(rec.description ?? '');
|
|
117
|
+
const affected = rec.affected_code ?? [];
|
|
118
|
+
f.root_cause.locations = affected.map((a) => ({ file: a.file, snippet: a.snippet }));
|
|
119
|
+
f.notes = `Materialized from ${kind} finding ${id}`;
|
|
120
|
+
return f;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Ensure a findings.json entry exists for `id`, materializing one from the
|
|
124
|
+
* source-specific record if needed. Idempotent: returns the existing entry
|
|
125
|
+
* untouched when present. Dispatches on id prefix.
|
|
126
|
+
*/
|
|
127
|
+
export function ensureFindingExists(outputDir, id) {
|
|
128
|
+
const findings = loadFindings(outputDir);
|
|
129
|
+
const existing = findings.findings.find((f) => f.id === id);
|
|
130
|
+
if (existing)
|
|
131
|
+
return existing;
|
|
132
|
+
const tracking = loadTracking(outputDir).findings.find((t) => t.id === id);
|
|
133
|
+
let materialized = null;
|
|
134
|
+
if (id.startsWith('SC-')) {
|
|
135
|
+
materialized = findingFromConformance(outputDir, id, tracking);
|
|
136
|
+
}
|
|
137
|
+
else if (id.startsWith('AA-')) {
|
|
138
|
+
materialized = findingFromAiOrGithub(outputDir, id, 'auditagent', tracking);
|
|
139
|
+
}
|
|
140
|
+
else if (id.startsWith('github-')) {
|
|
141
|
+
materialized = findingFromAiOrGithub(outputDir, id, 'github', tracking);
|
|
142
|
+
}
|
|
143
|
+
// Fallback: synthesize a minimal record from the tracking entry (covers
|
|
144
|
+
// manual `F*` ids restored from GitHub, or any source record we couldn't read).
|
|
145
|
+
if (!materialized) {
|
|
146
|
+
materialized = newEmptyFinding(id, tracking?.severity ?? 'Info');
|
|
147
|
+
if (tracking?.title)
|
|
148
|
+
materialized.title = tracking.title;
|
|
149
|
+
materialized.notes = tracking ? `Materialized from tracking entry ${id}` : '';
|
|
150
|
+
}
|
|
151
|
+
findings.findings.push(materialized);
|
|
152
|
+
writeJson(path.join(outputDir, 'findings.json'), findings);
|
|
153
|
+
return materialized;
|
|
154
|
+
}
|
|
155
|
+
// ─── Mutations ──────────────────────────────────────────────────────
|
|
156
|
+
/**
|
|
157
|
+
* Move an issue between board columns. Materializes a findings.json entry first
|
|
158
|
+
* (so non-manual cards become reportable when promoted to Verified), then flips
|
|
159
|
+
* the tracking status.
|
|
160
|
+
*
|
|
161
|
+
* Note: this does NOT edit the user's source files. Source annotation
|
|
162
|
+
* (`// @audit-issue-verified ...`) remains the responsibility of the
|
|
163
|
+
* /validate-issue skill, which the auditor invokes deliberately — a drag-drop
|
|
164
|
+
* on the board should never silently rewrite .sol files.
|
|
165
|
+
*/
|
|
166
|
+
export function moveIssue(outputDir, id, column) {
|
|
167
|
+
const nextStatus = COLUMN_TO_STATUS[column];
|
|
168
|
+
if (!nextStatus)
|
|
169
|
+
throw new Error(`Invalid column: ${column}`);
|
|
170
|
+
// Promoting to Verified should make the issue reportable.
|
|
171
|
+
if (column === 'verified')
|
|
172
|
+
ensureFindingExists(outputDir, id);
|
|
173
|
+
const tracking = loadTracking(outputDir);
|
|
174
|
+
let entry = tracking.findings.find((t) => t.id === id);
|
|
175
|
+
if (!entry) {
|
|
176
|
+
// The board only surfaces tracking entries, but be defensive: synthesize one
|
|
177
|
+
// from the (now-ensured) finding so a move never 404s on a real card.
|
|
178
|
+
const finding = ensureFindingExists(outputDir, id);
|
|
179
|
+
entry = {
|
|
180
|
+
id,
|
|
181
|
+
title: finding.title,
|
|
182
|
+
severity: finding.severity,
|
|
183
|
+
source: 'manual',
|
|
184
|
+
status: nextStatus,
|
|
185
|
+
poc_status: finding.poc?.status ?? 'not_started',
|
|
186
|
+
poc_file: finding.poc?.file ?? null,
|
|
187
|
+
duplicates: [],
|
|
188
|
+
duplicate_of: null,
|
|
189
|
+
notes: '',
|
|
190
|
+
};
|
|
191
|
+
tracking.findings.push(entry);
|
|
192
|
+
}
|
|
193
|
+
else {
|
|
194
|
+
entry.status = nextStatus;
|
|
195
|
+
}
|
|
196
|
+
// Clear a stale duplicate pointer when the card leaves the Duplicate column.
|
|
197
|
+
if (column !== 'duplicate' && entry.duplicate_of)
|
|
198
|
+
entry.duplicate_of = null;
|
|
199
|
+
writeJson(path.join(outputDir, 'tracking.json'), tracking);
|
|
200
|
+
return entry;
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Patch editable fields on an issue. Materializes a findings.json entry first so
|
|
204
|
+
* description / recommendation / resolution / update_from_client always land on
|
|
205
|
+
* a real record (not just non-manual cards' tracking rows). Title / severity /
|
|
206
|
+
* notes are mirrored on the tracking entry so the board reads current values
|
|
207
|
+
* without re-reading findings.json.
|
|
208
|
+
*/
|
|
209
|
+
export function patchIssue(outputDir, id, updates) {
|
|
210
|
+
const clean = {};
|
|
211
|
+
for (const key of EDITABLE_FIELDS) {
|
|
212
|
+
if (!(key in updates))
|
|
213
|
+
continue;
|
|
214
|
+
const value = updates[key];
|
|
215
|
+
if (key === 'severity' && value != null && !isValidSeverity(value)) {
|
|
216
|
+
throw new Error(`Invalid severity: ${String(value)}`);
|
|
217
|
+
}
|
|
218
|
+
if (key === 'resolution' && value != null && value !== '' && !isValidResolution(value)) {
|
|
219
|
+
throw new Error(`Invalid resolution: ${String(value)}`);
|
|
220
|
+
}
|
|
221
|
+
clean[key] = value;
|
|
222
|
+
}
|
|
223
|
+
if (Object.keys(clean).length === 0) {
|
|
224
|
+
throw new Error('No editable fields supplied');
|
|
225
|
+
}
|
|
226
|
+
const finding = ensureFindingExists(outputDir, id);
|
|
227
|
+
const findings = loadFindings(outputDir);
|
|
228
|
+
const target = findings.findings.find((f) => f.id === id) ?? finding;
|
|
229
|
+
for (const [key, value] of Object.entries(clean)) {
|
|
230
|
+
if (key === 'notes')
|
|
231
|
+
continue; // notes lives on tracking, not findings
|
|
232
|
+
if (key === 'resolution' && (value === '' || value == null)) {
|
|
233
|
+
delete target.resolution;
|
|
234
|
+
continue;
|
|
235
|
+
}
|
|
236
|
+
target[key] = value;
|
|
237
|
+
}
|
|
238
|
+
writeJson(path.join(outputDir, 'findings.json'), findings);
|
|
239
|
+
// Mirror title / severity / notes onto tracking.
|
|
240
|
+
const tracking = loadTracking(outputDir);
|
|
241
|
+
const entry = tracking.findings.find((t) => t.id === id);
|
|
242
|
+
if (entry) {
|
|
243
|
+
if ('title' in clean)
|
|
244
|
+
entry.title = clean.title;
|
|
245
|
+
if ('severity' in clean)
|
|
246
|
+
entry.severity = clean.severity;
|
|
247
|
+
if ('notes' in clean)
|
|
248
|
+
entry.notes = clean.notes;
|
|
249
|
+
writeJson(path.join(outputDir, 'tracking.json'), tracking);
|
|
250
|
+
}
|
|
251
|
+
return target;
|
|
252
|
+
}
|
|
253
|
+
//# sourceMappingURL=issues.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"issues.js","sourceRoot":"","sources":["../../src/core/issues.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -17,11 +17,12 @@ import { analyzeCommand } from './commands/analyze.js';
|
|
|
17
17
|
import { doctorCommand } from './commands/doctor.js';
|
|
18
18
|
import { aiStatusCommand } from './commands/ai-status.js';
|
|
19
19
|
import { updateCommand } from './commands/update.js';
|
|
20
|
+
import { issueCommand } from './commands/issue.js';
|
|
20
21
|
const program = new Command();
|
|
21
22
|
program
|
|
22
23
|
.name('hex')
|
|
23
24
|
.description('CLI toolkit for Solidity smart contract auditors')
|
|
24
|
-
.version('0.4.
|
|
25
|
+
.version('0.4.5');
|
|
25
26
|
program.addCommand(initCommand);
|
|
26
27
|
program.addCommand(statsCommand);
|
|
27
28
|
program.addCommand(depsCommand);
|
|
@@ -39,5 +40,6 @@ program.addCommand(analyzeCommand);
|
|
|
39
40
|
program.addCommand(doctorCommand);
|
|
40
41
|
program.addCommand(aiStatusCommand);
|
|
41
42
|
program.addCommand(updateCommand);
|
|
43
|
+
program.addCommand(issueCommand);
|
|
42
44
|
program.parse();
|
|
43
45
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAEnD,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,KAAK,CAAC;KACX,WAAW,CAAC,kDAAkD,CAAC;KAC/D,OAAO,CAAC,OAAO,CAAC,CAAC;AAEpB,OAAO,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC;AAChC,OAAO,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC;AACjC,OAAO,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC;AAChC,OAAO,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;AAClC,OAAO,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC;AACjC,OAAO,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC;AACjC,OAAO,CAAC,UAAU,CAAC,eAAe,CAAC,CAAC;AACpC,OAAO,CAAC,UAAU,CAAC,kBAAkB,CAAC,CAAC;AACvC,OAAO,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC;AACnC,OAAO,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC;AACnC,OAAO,CAAC,UAAU,CAAC,mBAAmB,CAAC,CAAC;AACxC,OAAO,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;AAClC,OAAO,CAAC,UAAU,CAAC,gBAAgB,CAAC,CAAC;AACrC,OAAO,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC;AACnC,OAAO,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;AAClC,OAAO,CAAC,UAAU,CAAC,eAAe,CAAC,CAAC;AACpC,OAAO,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;AAClC,OAAO,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC;AAEjC,OAAO,CAAC,KAAK,EAAE,CAAC"}
|
|
@@ -236,7 +236,9 @@ Also write a human-readable `.hex/spec-conformance.md` rendering the same data g
|
|
|
236
236
|
|
|
237
237
|
## Phase 6 — Materialize conformance items onto the board
|
|
238
238
|
|
|
239
|
-
For every item in `spec-conformance.json.items` with `status` of `DEVIATES` or `PARTIAL`, append a tracking entry to `.hex/tracking.json
|
|
239
|
+
For every item in `spec-conformance.json.items` with `status` of `DEVIATES` or `PARTIAL`, append a tracking entry to `.hex/tracking.json`.
|
|
240
|
+
|
|
241
|
+
**Wrapper (required):** `.hex/tracking.json` MUST be `{ "findings": [<TrackingEntry>, ...] }`. The wrapper key is `findings` (NOT `issues`) — the dashboard's `TrackingFile` type and the `/api/issues` routes reject any other shape. If the file does not exist, create it as `{ "findings": [] }` and then append. If it exists, parse it, append to the `findings` array, and write it back. Match the per-entry schema below exactly.
|
|
240
242
|
|
|
241
243
|
```json
|
|
242
244
|
{
|
|
@@ -156,61 +156,44 @@ Within candidates:
|
|
|
156
156
|
- Has `github.issue_number` → update via `gh issue edit`.
|
|
157
157
|
- No `github.issue_number` → create via `gh issue create`.
|
|
158
158
|
|
|
159
|
-
**3b. Render the body** (write to a temp file, then `--body-file`):
|
|
159
|
+
**3b. Render the body** (write to a temp file, then `--body-file`). Use this exact template — nothing more, nothing less in the visible body. It mirrors `dashboard/lib/finding-markdown.ts::findingToGithubBody`, so the board's "Copy as HackMD" output and the pushed issue stay identical:
|
|
160
160
|
|
|
161
161
|
```markdown
|
|
162
|
-
**
|
|
162
|
+
**File(s)**: [`<file>`](<github-blob-url-or-empty>)
|
|
163
163
|
|
|
164
|
-
<finding.description>
|
|
164
|
+
**Description**: <finding.description>
|
|
165
165
|
|
|
166
|
-
|
|
166
|
+
**Recommendation(s)**: <finding.recommendation>
|
|
167
167
|
|
|
168
|
-
<
|
|
169
|
-
**`<location.file>`**
|
|
168
|
+
**Status**: <finding.resolution or "Unresolved">
|
|
170
169
|
|
|
171
|
-
|
|
172
|
-
<location.snippet>
|
|
173
|
-
```
|
|
174
|
-
</for>
|
|
175
|
-
|
|
176
|
-
### Recommendation
|
|
177
|
-
|
|
178
|
-
<finding.recommendation>
|
|
179
|
-
|
|
180
|
-
---
|
|
181
|
-
|
|
182
|
-
*Synced from Hex audit `<config.project.name>` at commit `<config.project.commit>`.*
|
|
170
|
+
**Update from the client**: <finding.update_from_client or empty>
|
|
183
171
|
|
|
184
172
|
<!-- hex-finding-id: <finding.id> -->
|
|
185
173
|
```
|
|
186
174
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
**
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
```
|
|
194
|
-
|
|
195
|
-
Apply via repeated `--label` flags.
|
|
175
|
+
Rules:
|
|
176
|
+
- **File(s)** — one markdown link per affected file in `root_cause.locations[]`, comma-separated when there is more than one: `` [`src/Vault.sol`](url1), [`src/MockToken.sol`](url2) ``. Build each URL as `<settings.report.repository_url>/blob/<settings.report.initial_commit>/<file>`. If either `repository_url` or `initial_commit` is missing from `config.json`, use an empty link target: `` [`<file>`]() ``.
|
|
177
|
+
- **Status** — the finding's `resolution` field if set, otherwise the literal `Unresolved`.
|
|
178
|
+
- **Update from the client** — the finding's `update_from_client` field if set, otherwise leave it blank after the colon.
|
|
179
|
+
- Do NOT add a `**Severity:**` line (severity is already in the title), an `### Affected code` section, code blocks, or a "Synced from Hex" attribution line.
|
|
180
|
+
- The `<!-- hex-finding-id: <finding.id> -->` HTML comment at the very bottom is **mandatory and load-bearing** — it is the round-trip dedup key, invisible in GitHub's rendered view. Never omit it.
|
|
196
181
|
|
|
197
|
-
**
|
|
182
|
+
**3c. Create or update — no labels.** Hex does not apply, add, or remove labels. The target repo's label set is the repo owner's concern; assuming labels exist (e.g. `severity:critical`) makes `gh issue create` fail when they don't.
|
|
198
183
|
|
|
199
184
|
Create:
|
|
200
185
|
```bash
|
|
201
|
-
gh issue create --repo <repo> --title "[<Severity>] <title>" --body-file <tmp>
|
|
202
|
-
--label "hex" --label "audit" --label "severity:..." --label "source:..." --label "status:..."
|
|
186
|
+
gh issue create --repo <repo> --title "[<Severity>] <title>" --body-file <tmp>
|
|
203
187
|
```
|
|
204
188
|
|
|
205
189
|
Parse the returned URL to extract the issue number; update the local finding's `github` block.
|
|
206
190
|
|
|
207
191
|
Update existing:
|
|
208
192
|
```bash
|
|
209
|
-
gh issue edit <num> --repo <repo> --title "[<Severity>] <title>" --body-file <tmp>
|
|
210
|
-
--add-label "severity:..." --add-label "status:..."
|
|
193
|
+
gh issue edit <num> --repo <repo> --title "[<Severity>] <title>" --body-file <tmp>
|
|
211
194
|
```
|
|
212
195
|
|
|
213
|
-
|
|
196
|
+
(`settings.github.default_labels` in config is retained for backwards compatibility but is no longer applied.)
|
|
214
197
|
|
|
215
198
|
If push fails for any single finding: capture stderr, set its `github.sync_status` to `conflict`, append a one-line error, continue with the next finding. Never abort the whole sync on one failure.
|
|
216
199
|
|
|
@@ -261,6 +244,6 @@ GitHub sync complete (<repo>)
|
|
|
261
244
|
|
|
262
245
|
- Does not authenticate (use `gh auth login` once).
|
|
263
246
|
- Does not post comments (auditors discuss inside GitHub).
|
|
264
|
-
- Does not create labels (
|
|
247
|
+
- Does not apply, create, or remove labels (the repo owner manages its own labels).
|
|
265
248
|
- Does not delete remote issues.
|
|
266
249
|
- Does not push `rejected`, `unverified`, or `duplicate` findings.
|