codeproof 1.0.4 → 1.1.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.
Files changed (42) hide show
  1. package/bin/codeproof.js +62 -60
  2. package/commands/apply.js +32 -32
  3. package/commands/help.js +34 -0
  4. package/commands/ignore.js +32 -32
  5. package/commands/init.js +110 -106
  6. package/commands/moveSecret.js +254 -202
  7. package/commands/reportDashboard.js +65 -65
  8. package/commands/run.js +234 -234
  9. package/commands/whoami.js +19 -19
  10. package/core/boundaries.md +26 -26
  11. package/core/enforcement.js +51 -51
  12. package/core/featureFlags.js +25 -25
  13. package/core/identity.js +78 -78
  14. package/core/safetyGuards.js +58 -58
  15. package/engine/aiAnalyzer.js +143 -143
  16. package/engine/aiEscalation.js +6 -6
  17. package/engine/contextBuilder.js +65 -65
  18. package/engine/decisionMerger.js +30 -30
  19. package/engine/ruleEngine.js +52 -52
  20. package/hooks/preCommit.js +93 -93
  21. package/package.json +16 -16
  22. package/reporting/reportBuilder.js +112 -112
  23. package/reporting/reportReader.js +49 -49
  24. package/reporting/reportWriter.js +104 -91
  25. package/rules/dangerousUsageRule.js +11 -11
  26. package/rules/insecureConfigRule.js +11 -11
  27. package/rules/regexPatterns.js +53 -53
  28. package/rules/ruleUtils.js +58 -58
  29. package/rules/secretRule.js +21 -21
  30. package/ui/banner.js +36 -0
  31. package/ui/formatting.js +76 -0
  32. package/ui/welcomeScreen.js +42 -42
  33. package/utils/apiClient.js +96 -96
  34. package/utils/envManager.js +48 -48
  35. package/utils/fileRewriter.js +145 -145
  36. package/utils/fileScanner.js +40 -40
  37. package/utils/files.js +50 -50
  38. package/utils/git.js +63 -63
  39. package/utils/gitIgnore.js +55 -55
  40. package/utils/logger.js +25 -25
  41. package/utils/projectType.js +20 -20
  42. package/.env +0 -1
package/bin/codeproof.js CHANGED
@@ -1,61 +1,63 @@
1
1
  #!/usr/bin/env node
2
- import { runInit } from "../commands/init.js";
3
- import { runCli } from "../commands/run.js";
4
- import { runReportDashboard } from "../commands/reportDashboard.js";
5
- import { runMoveSecret } from "../commands/moveSecret.js";
6
- import { runWhoAmI } from "../commands/whoami.js";
7
- import { runIgnore } from "../commands/ignore.js";
8
- import { runApply } from "../commands/apply.js";
9
- import { logError, logInfo } from "../utils/logger.js";
10
-
11
- const [, , command, ...args] = process.argv;
12
-
13
- async function main() {
14
- if (!command || command === "-h" || command === "--help") {
15
- logInfo("Usage: codeproof <command>\n\nCommands:\n init Initialize CodeProof in a Git repository\n run Run CodeProof checks (stub)\n report@dashboard Send latest report and show dashboard link\n move-secret Move high-confidence secrets to .env\n ignore Temporarily disable commit enforcement\n apply Re-enable commit enforcement\n whoami Show the local CodeProof client ID");
16
- process.exit(0);
17
- }
18
-
19
- if (command === "init") {
20
- await runInit({ args, cwd: process.cwd() });
21
- return;
22
- }
23
-
24
- if (command === "run") {
25
- await runCli({ args, cwd: process.cwd() });
26
- return;
27
- }
28
-
29
- if (command === "report@dashboard") {
30
- await runReportDashboard({ args, cwd: process.cwd() });
31
- return;
32
- }
33
-
34
- if (command === "move-secret") {
35
- await runMoveSecret({ args, cwd: process.cwd() });
36
- return;
37
- }
38
-
39
- if (command === "ignore") {
40
- await runIgnore({ args, cwd: process.cwd() });
41
- return;
42
- }
43
-
44
- if (command === "apply") {
45
- await runApply({ args, cwd: process.cwd() });
46
- return;
47
- }
48
-
49
- if (command === "whoami") {
50
- await runWhoAmI();
51
- return;
52
- }
53
-
54
- logError(`Unknown command: ${command}`);
55
- process.exit(1);
56
- }
57
-
58
- main().catch((error) => {
59
- logError(error?.message || String(error));
60
- process.exit(1);
61
- });
2
+ import { runInit } from "../commands/init.js";
3
+ import { runCli } from "../commands/run.js";
4
+ import { runReportDashboard } from "../commands/reportDashboard.js";
5
+ import { runMoveSecret } from "../commands/moveSecret.js";
6
+ import { runWhoAmI } from "../commands/whoami.js";
7
+ import { runIgnore } from "../commands/ignore.js";
8
+ import { runApply } from "../commands/apply.js";
9
+ import { runHelp } from "../commands/help.js";
10
+ import { logError } from "../utils/logger.js";
11
+
12
+ const [, , command, ...args] = process.argv;
13
+
14
+ async function main() {
15
+ // Show help for no command or explicit help flags
16
+ if (!command || command === "-h" || command === "--help" || command === "help") {
17
+ await runHelp();
18
+ return;
19
+ }
20
+
21
+ if (command === "init") {
22
+ await runInit({ args, cwd: process.cwd() });
23
+ return;
24
+ }
25
+
26
+ if (command === "run") {
27
+ await runCli({ args, cwd: process.cwd() });
28
+ return;
29
+ }
30
+
31
+ if (command === "report@dashboard") {
32
+ await runReportDashboard({ args, cwd: process.cwd() });
33
+ return;
34
+ }
35
+
36
+ if (command === "move-secret") {
37
+ await runMoveSecret({ args, cwd: process.cwd() });
38
+ return;
39
+ }
40
+
41
+ if (command === "ignore") {
42
+ await runIgnore({ args, cwd: process.cwd() });
43
+ return;
44
+ }
45
+
46
+ if (command === "apply") {
47
+ await runApply({ args, cwd: process.cwd() });
48
+ return;
49
+ }
50
+
51
+ if (command === "whoami") {
52
+ await runWhoAmI();
53
+ return;
54
+ }
55
+
56
+ logError(`Unknown command: ${command}`);
57
+ process.exit(1);
58
+ }
59
+
60
+ main().catch((error) => {
61
+ logError(error?.message || String(error));
62
+ process.exit(1);
63
+ });
package/commands/apply.js CHANGED
@@ -1,32 +1,32 @@
1
- import { ensureGitRepo, getGitRoot } from "../utils/git.js";
2
- import { logError, logInfo, logSuccess, logWarn } from "../utils/logger.js";
3
- import { getEnforcementState, setEnforcementState } from "../core/enforcement.js";
4
-
5
- export async function runApply({ cwd }) {
6
- // Re-enable enforcement explicitly to restore pre-commit blocking.
7
- ensureGitRepo(cwd);
8
- const gitRoot = getGitRoot(cwd);
9
-
10
- let current = "enabled";
11
- try {
12
- current = getEnforcementState(gitRoot);
13
- } catch (error) {
14
- logError(error?.message || "Unable to read codeproof.config.json.");
15
- process.exit(1);
16
- }
17
-
18
- if (current === "enabled") {
19
- logWarn("CodeProof enforcement is already enabled.");
20
- return;
21
- }
22
-
23
- try {
24
- setEnforcementState(gitRoot, "enabled");
25
- } catch (error) {
26
- logError(error?.message || "Unable to update codeproof.config.json.");
27
- process.exit(1);
28
- }
29
-
30
- logSuccess("CodeProof enforcement re-enabled.");
31
- logInfo("Pre-commit protection active.");
32
- }
1
+ import { ensureGitRepo, getGitRoot } from "../utils/git.js";
2
+ import { logError, logInfo, logSuccess, logWarn } from "../utils/logger.js";
3
+ import { getEnforcementState, setEnforcementState } from "../core/enforcement.js";
4
+
5
+ export async function runApply({ cwd }) {
6
+ // Re-enable enforcement explicitly to restore pre-commit blocking.
7
+ ensureGitRepo(cwd);
8
+ const gitRoot = getGitRoot(cwd);
9
+
10
+ let current = "enabled";
11
+ try {
12
+ current = getEnforcementState(gitRoot);
13
+ } catch (error) {
14
+ logError(error?.message || "Unable to read codeproof.config.json.");
15
+ process.exit(1);
16
+ }
17
+
18
+ if (current === "enabled") {
19
+ logWarn("CodeProof enforcement is already enabled.");
20
+ return;
21
+ }
22
+
23
+ try {
24
+ setEnforcementState(gitRoot, "enabled");
25
+ } catch (error) {
26
+ logError(error?.message || "Unable to update codeproof.config.json.");
27
+ process.exit(1);
28
+ }
29
+
30
+ logSuccess("CodeProof enforcement re-enabled.");
31
+ logInfo("Pre-commit protection active.");
32
+ }
@@ -0,0 +1,34 @@
1
+ // Help command implementation
2
+ // Displays banner and available commands
3
+
4
+ import { displayBanner } from "../ui/banner.js";
5
+ import { formatBlock } from "../ui/formatting.js";
6
+
7
+ const HELP_TEXT = `Usage: codeproof <command>
8
+
9
+ Commands:
10
+ init Initialize CodeProof in a Git repository
11
+ run Run CodeProof checks
12
+ report@dashboard Send latest report and show dashboard link
13
+ move-secret Move high-risk secrets to .env
14
+ ignore Temporarily disable commit enforcement
15
+ apply Re-enable commit enforcement
16
+ whoami Show the local CodeProof client ID
17
+ help Show this help menu
18
+ -h, --help Show this help menu
19
+
20
+ Examples:
21
+ codeproof init
22
+ codeproof run
23
+ codeproof move-secret --yes
24
+ codeproof help
25
+ `;
26
+
27
+ /**
28
+ * Display help information with banner
29
+ */
30
+ export async function runHelp() {
31
+ displayBanner();
32
+ formatBlock(HELP_TEXT);
33
+ process.exit(0);
34
+ }
@@ -1,32 +1,32 @@
1
- import { ensureGitRepo, getGitRoot } from "../utils/git.js";
2
- import { logError, logInfo, logSuccess, logWarn } from "../utils/logger.js";
3
- import { getEnforcementState, setEnforcementState } from "../core/enforcement.js";
4
-
5
- export async function runIgnore({ cwd }) {
6
- // Controlled bypass: disabling enforcement is explicit and project-scoped.
7
- ensureGitRepo(cwd);
8
- const gitRoot = getGitRoot(cwd);
9
-
10
- let current = "enabled";
11
- try {
12
- current = getEnforcementState(gitRoot);
13
- } catch (error) {
14
- logError(error?.message || "Unable to read codeproof.config.json.");
15
- process.exit(1);
16
- }
17
-
18
- if (current === "disabled") {
19
- logWarn("CodeProof enforcement is already disabled.");
20
- return;
21
- }
22
-
23
- try {
24
- setEnforcementState(gitRoot, "disabled");
25
- } catch (error) {
26
- logError(error?.message || "Unable to update codeproof.config.json.");
27
- process.exit(1);
28
- }
29
-
30
- logSuccess("CodeProof enforcement disabled.");
31
- logInfo("Commits will not be blocked until `codeproof apply` is run.");
32
- }
1
+ import { ensureGitRepo, getGitRoot } from "../utils/git.js";
2
+ import { logError, logInfo, logSuccess, logWarn } from "../utils/logger.js";
3
+ import { getEnforcementState, setEnforcementState } from "../core/enforcement.js";
4
+
5
+ export async function runIgnore({ cwd }) {
6
+ // Controlled bypass: disabling enforcement is explicit and project-scoped.
7
+ ensureGitRepo(cwd);
8
+ const gitRoot = getGitRoot(cwd);
9
+
10
+ let current = "enabled";
11
+ try {
12
+ current = getEnforcementState(gitRoot);
13
+ } catch (error) {
14
+ logError(error?.message || "Unable to read codeproof.config.json.");
15
+ process.exit(1);
16
+ }
17
+
18
+ if (current === "disabled") {
19
+ logWarn("CodeProof enforcement is already disabled.");
20
+ return;
21
+ }
22
+
23
+ try {
24
+ setEnforcementState(gitRoot, "disabled");
25
+ } catch (error) {
26
+ logError(error?.message || "Unable to update codeproof.config.json.");
27
+ process.exit(1);
28
+ }
29
+
30
+ logSuccess("CodeProof enforcement disabled.");
31
+ logInfo("Commits will not be blocked until `codeproof apply` is run.");
32
+ }
package/commands/init.js CHANGED
@@ -1,107 +1,111 @@
1
- import path from "path";
2
- import fs from "fs";
3
- import { ensureGitRepo, getGitRoot } from "../utils/git.js";
4
- import { logInfo, logSuccess, logWarn } from "../utils/logger.js";
5
- import { detectProjectType } from "../utils/projectType.js";
6
- import { installPreCommitHook } from "../hooks/preCommit.js";
7
- import { showWelcomeScreen } from "../ui/welcomeScreen.js";
8
- import { getClientId } from "../core/identity.js";
9
- import { randomUUID } from "crypto";
10
-
11
-
12
-
13
- export async function runInit({ cwd }) {
14
- logInfo("Initializing CodeProof...");
15
-
16
- getClientId();
17
-
18
- ensureGitRepo(cwd);
19
- logSuccess("Git repository detected.");
20
-
21
- const gitRoot = getGitRoot(cwd);
22
- logInfo(`Project root: ${gitRoot}`);
23
-
24
- const projectType = detectProjectType(gitRoot);
25
- logInfo(`Detected project type: ${projectType}`);
26
-
27
- const configPath = path.join(gitRoot, "codeproof.config.json");
28
- // Avoid overwriting user configuration to keep init idempotent.
29
- if (fs.existsSync(configPath)) {
30
- let updated = false;
31
- try {
32
- const raw = fs.readFileSync(configPath, "utf8");
33
- const existing = JSON.parse(raw);
34
- if (!existing.projectId) {
35
- existing.projectId = randomUUID();
36
- updated = true;
37
- fs.writeFileSync(configPath, JSON.stringify(existing, null, 2) + "\n", "utf8");
38
- }
39
- } catch {
40
- logWarn("Config already exists but could not be updated.");
41
- }
42
-
43
- if (updated) {
44
- logSuccess("Added projectId to codeproof.config.json");
45
- } else {
46
- logWarn("Config already exists. Skipping creation.");
47
- }
48
- } else {
49
- const config = {
50
- projectId: randomUUID(),
51
- projectType,
52
- scanMode: "staged",
53
- enforcement: "enabled",
54
- features: {
55
- reporting: true,
56
- integration: false,
57
- aiEscalation: false,
58
- secretRemediation: false
59
- },
60
- integration: {
61
- enabled: false,
62
- endpointUrl: ""
63
- },
64
- severityRules: {
65
- block: [],
66
- warn: [],
67
- allow: []
68
- }
69
- };
70
- fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n", "utf8");
71
- logSuccess("Created codeproof.config.json");
72
- }
73
-
74
- try {
75
- const raw = fs.readFileSync(configPath, "utf8");
76
- const existing = JSON.parse(raw);
77
- if (!existing.enforcement) {
78
- existing.enforcement = "enabled";
79
- fs.writeFileSync(configPath, JSON.stringify(existing, null, 2) + "\n", "utf8");
80
- logSuccess("Added enforcement=enabled to codeproof.config.json");
81
- }
82
- } catch {
83
- logWarn("Unable to update enforcement in codeproof.config.json.");
84
- }
85
-
86
- installPreCommitHook(gitRoot);
87
- logSuccess("Pre-commit hook installed.");
88
-
89
- logSuccess("CodeProof initialization complete.");
90
-
91
- let scanMode = "staged";
92
- try {
93
- const configRaw = fs.readFileSync(configPath, "utf8");
94
- const parsed = JSON.parse(configRaw);
95
- if (parsed?.scanMode) {
96
- scanMode = String(parsed.scanMode).toLowerCase();
97
- }
98
- } catch {
99
- // UX: welcome message should never fail init; fall back to defaults for display.
100
- }
101
-
102
- showWelcomeScreen({
103
- projectType,
104
- scanMode,
105
- configPath
106
- });
1
+ import path from "path";
2
+ import fs from "fs";
3
+ import { ensureGitRepo, getGitRoot } from "../utils/git.js";
4
+ import { logInfo, logSuccess, logWarn } from "../utils/logger.js";
5
+ import { detectProjectType } from "../utils/projectType.js";
6
+ import { installPreCommitHook } from "../hooks/preCommit.js";
7
+ import { showWelcomeScreen } from "../ui/welcomeScreen.js";
8
+ import { displayBanner } from "../ui/banner.js";
9
+ import { getClientId } from "../core/identity.js";
10
+ import { randomUUID } from "crypto";
11
+
12
+
13
+
14
+ export async function runInit({ cwd }) {
15
+ // Display banner at the start of initialization
16
+ displayBanner();
17
+
18
+ logInfo("Initializing CodeProof...");
19
+
20
+ getClientId();
21
+
22
+ ensureGitRepo(cwd);
23
+ logSuccess("Git repository detected.");
24
+
25
+ const gitRoot = getGitRoot(cwd);
26
+ logInfo(`Project root: ${gitRoot}`);
27
+
28
+ const projectType = detectProjectType(gitRoot);
29
+ logInfo(`Detected project type: ${projectType}`);
30
+
31
+ const configPath = path.join(gitRoot, "codeproof.config.json");
32
+ // Avoid overwriting user configuration to keep init idempotent.
33
+ if (fs.existsSync(configPath)) {
34
+ let updated = false;
35
+ try {
36
+ const raw = fs.readFileSync(configPath, "utf8");
37
+ const existing = JSON.parse(raw);
38
+ if (!existing.projectId) {
39
+ existing.projectId = randomUUID();
40
+ updated = true;
41
+ fs.writeFileSync(configPath, JSON.stringify(existing, null, 2) + "\n", "utf8");
42
+ }
43
+ } catch {
44
+ logWarn("Config already exists but could not be updated.");
45
+ }
46
+
47
+ if (updated) {
48
+ logSuccess("Added projectId to codeproof.config.json");
49
+ } else {
50
+ logWarn("Config already exists. Skipping creation.");
51
+ }
52
+ } else {
53
+ const config = {
54
+ projectId: randomUUID(),
55
+ projectType,
56
+ scanMode: "staged",
57
+ enforcement: "enabled",
58
+ features: {
59
+ reporting: true,
60
+ integration: false,
61
+ aiEscalation: false,
62
+ secretRemediation: false
63
+ },
64
+ integration: {
65
+ enabled: false,
66
+ endpointUrl: ""
67
+ },
68
+ severityRules: {
69
+ block: [],
70
+ warn: [],
71
+ allow: []
72
+ }
73
+ };
74
+ fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n", "utf8");
75
+ logSuccess("Created codeproof.config.json");
76
+ }
77
+
78
+ try {
79
+ const raw = fs.readFileSync(configPath, "utf8");
80
+ const existing = JSON.parse(raw);
81
+ if (!existing.enforcement) {
82
+ existing.enforcement = "enabled";
83
+ fs.writeFileSync(configPath, JSON.stringify(existing, null, 2) + "\n", "utf8");
84
+ logSuccess("Added enforcement=enabled to codeproof.config.json");
85
+ }
86
+ } catch {
87
+ logWarn("Unable to update enforcement in codeproof.config.json.");
88
+ }
89
+
90
+ installPreCommitHook(gitRoot);
91
+ logSuccess("Pre-commit hook installed.");
92
+
93
+ logSuccess("CodeProof initialization complete.");
94
+
95
+ let scanMode = "staged";
96
+ try {
97
+ const configRaw = fs.readFileSync(configPath, "utf8");
98
+ const parsed = JSON.parse(configRaw);
99
+ if (parsed?.scanMode) {
100
+ scanMode = String(parsed.scanMode).toLowerCase();
101
+ }
102
+ } catch {
103
+ // UX: welcome message should never fail init; fall back to defaults for display.
104
+ }
105
+
106
+ showWelcomeScreen({
107
+ projectType,
108
+ scanMode,
109
+ configPath
110
+ });
107
111
  }