codeproof 1.0.1 → 1.0.2
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/codeproof.js +13 -1
- package/commands/apply.js +32 -0
- package/commands/ignore.js +32 -0
- package/commands/init.js +13 -0
- package/commands/moveSecret.js +2 -20
- package/commands/run.js +16 -1
- package/core/enforcement.js +51 -0
- package/hooks/preCommit.js +28 -2
- package/package.json +1 -1
package/bin/codeproof.js
CHANGED
|
@@ -4,13 +4,15 @@ import { runCli } from "../commands/run.js";
|
|
|
4
4
|
import { runReportDashboard } from "../commands/reportDashboard.js";
|
|
5
5
|
import { runMoveSecret } from "../commands/moveSecret.js";
|
|
6
6
|
import { runWhoAmI } from "../commands/whoami.js";
|
|
7
|
+
import { runIgnore } from "../commands/ignore.js";
|
|
8
|
+
import { runApply } from "../commands/apply.js";
|
|
7
9
|
import { logError, logInfo } from "../utils/logger.js";
|
|
8
10
|
|
|
9
11
|
const [, , command, ...args] = process.argv;
|
|
10
12
|
|
|
11
13
|
async function main() {
|
|
12
14
|
if (!command || command === "-h" || command === "--help") {
|
|
13
|
-
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 whoami Show the local CodeProof client ID");
|
|
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");
|
|
14
16
|
process.exit(0);
|
|
15
17
|
}
|
|
16
18
|
|
|
@@ -34,6 +36,16 @@ async function main() {
|
|
|
34
36
|
return;
|
|
35
37
|
}
|
|
36
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
|
+
|
|
37
49
|
if (command === "whoami") {
|
|
38
50
|
await runWhoAmI();
|
|
39
51
|
return;
|
|
@@ -0,0 +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
|
+
}
|
|
@@ -0,0 +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
|
+
}
|
package/commands/init.js
CHANGED
|
@@ -50,6 +50,7 @@ export async function runInit({ cwd }) {
|
|
|
50
50
|
projectId: randomUUID(),
|
|
51
51
|
projectType,
|
|
52
52
|
scanMode: "staged",
|
|
53
|
+
enforcement: "enabled",
|
|
53
54
|
features: {
|
|
54
55
|
reporting: true,
|
|
55
56
|
integration: false,
|
|
@@ -70,6 +71,18 @@ export async function runInit({ cwd }) {
|
|
|
70
71
|
logSuccess("Created codeproof.config.json");
|
|
71
72
|
}
|
|
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
|
+
|
|
73
86
|
installPreCommitHook(gitRoot);
|
|
74
87
|
logSuccess("Pre-commit hook installed.");
|
|
75
88
|
|
package/commands/moveSecret.js
CHANGED
|
@@ -8,6 +8,7 @@ import { ensureEnvFile, readEnvKeys, appendEnvEntries } from "../utils/envManage
|
|
|
8
8
|
import { backupFileOnce, extractSecretValueFromLine, replaceSecretInFile } from "../utils/fileRewriter.js";
|
|
9
9
|
import { resolveFeatureFlags, isVerbose } from "../core/featureFlags.js";
|
|
10
10
|
import { reportFeatureDisabled, warnExperimentalOnce } from "../core/safetyGuards.js";
|
|
11
|
+
import { readLatestReport } from "../reporting/reportReader.js";
|
|
11
12
|
|
|
12
13
|
const TEST_PATH_HINTS = [
|
|
13
14
|
"test",
|
|
@@ -37,24 +38,6 @@ function isIgnoredPath(filePath, excludes) {
|
|
|
37
38
|
return false;
|
|
38
39
|
}
|
|
39
40
|
|
|
40
|
-
function readLatestReport(reportPath) {
|
|
41
|
-
if (!fs.existsSync(reportPath)) {
|
|
42
|
-
return null;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
const content = fs.readFileSync(reportPath, "utf8");
|
|
46
|
-
const lines = content.split(/\r?\n/).filter(Boolean);
|
|
47
|
-
if (lines.length === 0) {
|
|
48
|
-
return null;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
try {
|
|
52
|
-
return JSON.parse(lines[lines.length - 1]);
|
|
53
|
-
} catch {
|
|
54
|
-
return null;
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
41
|
function confirmProceed(message) {
|
|
59
42
|
return new Promise((resolve) => {
|
|
60
43
|
const rl = readline.createInterface({
|
|
@@ -73,7 +56,6 @@ export async function runMoveSecret({ cwd }) {
|
|
|
73
56
|
// Boundary: remediation reads reports only and must not depend on analysis state.
|
|
74
57
|
ensureGitRepo(cwd);
|
|
75
58
|
const gitRoot = getGitRoot(cwd);
|
|
76
|
-
const reportPath = path.join(gitRoot, "codeproof-report.log");
|
|
77
59
|
const configPath = path.join(gitRoot, "codeproof.config.json");
|
|
78
60
|
let config = {};
|
|
79
61
|
try {
|
|
@@ -92,7 +74,7 @@ export async function runMoveSecret({ cwd }) {
|
|
|
92
74
|
}
|
|
93
75
|
|
|
94
76
|
warnExperimentalOnce("Experimental feature enabled: move-secret.", logWarn);
|
|
95
|
-
const latestReport = readLatestReport(
|
|
77
|
+
const latestReport = readLatestReport(gitRoot)?.report || null;
|
|
96
78
|
|
|
97
79
|
if (!latestReport || !Array.isArray(latestReport.findings)) {
|
|
98
80
|
logWarn("No reports found. Run 'codeproof run' first.");
|
package/commands/run.js
CHANGED
|
@@ -12,6 +12,7 @@ import { writeReport } from "../reporting/reportWriter.js";
|
|
|
12
12
|
import { sendReportToServer } from "../utils/apiClient.js";
|
|
13
13
|
import { resolveFeatureFlags, isVerbose } from "../core/featureFlags.js";
|
|
14
14
|
import { getClientId } from "../core/identity.js";
|
|
15
|
+
import { getEnforcementState } from "../core/enforcement.js";
|
|
15
16
|
import {
|
|
16
17
|
reportFeatureDisabled,
|
|
17
18
|
warnExperimentalOnce,
|
|
@@ -36,7 +37,7 @@ function readConfig(configPath) {
|
|
|
36
37
|
}
|
|
37
38
|
}
|
|
38
39
|
|
|
39
|
-
export async function runCli({ cwd }) {
|
|
40
|
+
export async function runCli({ args = [], cwd }) {
|
|
40
41
|
// Boundary: CLI orchestration only. Avoid importing this module in lower layers.
|
|
41
42
|
logInfo("CodeProof run started.");
|
|
42
43
|
|
|
@@ -46,6 +47,20 @@ export async function runCli({ cwd }) {
|
|
|
46
47
|
const config = readConfig(configPath);
|
|
47
48
|
const features = resolveFeatureFlags(config);
|
|
48
49
|
const verbose = isVerbose(config);
|
|
50
|
+
let enforcement = "enabled";
|
|
51
|
+
try {
|
|
52
|
+
enforcement = getEnforcementState(gitRoot);
|
|
53
|
+
} catch (error) {
|
|
54
|
+
logError(error?.message || "Unable to read enforcement state.");
|
|
55
|
+
process.exit(1);
|
|
56
|
+
}
|
|
57
|
+
const isPreCommit = args.includes("--precommit") || Boolean(process.env.CODEPROOF_PRECOMMIT);
|
|
58
|
+
|
|
59
|
+
if (isPreCommit && enforcement === "disabled") {
|
|
60
|
+
logWarn("CodeProof enforcement is temporarily disabled.");
|
|
61
|
+
logInfo("Commit allowed.");
|
|
62
|
+
process.exit(0);
|
|
63
|
+
}
|
|
49
64
|
|
|
50
65
|
if (!config.scanMode) {
|
|
51
66
|
logError("Config missing scanMode. Expected 'staged' or 'full'.");
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
|
|
4
|
+
const ENFORCEMENT_ENABLED = "enabled";
|
|
5
|
+
const ENFORCEMENT_DISABLED = "disabled";
|
|
6
|
+
|
|
7
|
+
function getConfigPath(gitRoot) {
|
|
8
|
+
return path.join(gitRoot, "codeproof.config.json");
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function readConfig(gitRoot) {
|
|
12
|
+
const configPath = getConfigPath(gitRoot);
|
|
13
|
+
if (!fs.existsSync(configPath)) {
|
|
14
|
+
const error = new Error("Missing codeproof.config.json. Run codeproof init first.");
|
|
15
|
+
error.code = "CODEPROOF_CONFIG_MISSING";
|
|
16
|
+
throw error;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
try {
|
|
20
|
+
const raw = fs.readFileSync(configPath, "utf8");
|
|
21
|
+
return JSON.parse(raw);
|
|
22
|
+
} catch {
|
|
23
|
+
const error = new Error("Invalid codeproof.config.json. Please fix the file.");
|
|
24
|
+
error.code = "CODEPROOF_CONFIG_INVALID";
|
|
25
|
+
throw error;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function writeConfig(gitRoot, config) {
|
|
30
|
+
const configPath = getConfigPath(gitRoot);
|
|
31
|
+
fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n", "utf8");
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function getEnforcementState(gitRoot) {
|
|
35
|
+
const config = readConfig(gitRoot);
|
|
36
|
+
const enforcement = String(config.enforcement || ENFORCEMENT_ENABLED).toLowerCase();
|
|
37
|
+
return enforcement === ENFORCEMENT_DISABLED ? ENFORCEMENT_DISABLED : ENFORCEMENT_ENABLED;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function setEnforcementState(gitRoot, nextState) {
|
|
41
|
+
const config = readConfig(gitRoot);
|
|
42
|
+
const normalized = String(nextState || "").toLowerCase();
|
|
43
|
+
const enforcement = normalized === ENFORCEMENT_DISABLED
|
|
44
|
+
? ENFORCEMENT_DISABLED
|
|
45
|
+
: ENFORCEMENT_ENABLED;
|
|
46
|
+
|
|
47
|
+
// Security: explicit state keeps this a reversible bypass, not a silent disable.
|
|
48
|
+
const updated = { ...config, enforcement };
|
|
49
|
+
writeConfig(gitRoot, updated);
|
|
50
|
+
return enforcement;
|
|
51
|
+
}
|
package/hooks/preCommit.js
CHANGED
|
@@ -12,7 +12,20 @@ function getHookBlock() {
|
|
|
12
12
|
return [
|
|
13
13
|
"",
|
|
14
14
|
HOOK_MARKER,
|
|
15
|
-
"
|
|
15
|
+
"GIT_ROOT=$(git rev-parse --show-toplevel 2>/dev/null)",
|
|
16
|
+
"if [ -n \"$GIT_ROOT\" ]; then",
|
|
17
|
+
" cd \"$GIT_ROOT\" || exit 1",
|
|
18
|
+
"fi",
|
|
19
|
+
"CONFIG_PATH=\"$GIT_ROOT/codeproof.config.json\"",
|
|
20
|
+
"if [ -f \"$CONFIG_PATH\" ]; then",
|
|
21
|
+
" ENFORCEMENT=$(node -e \"const fs=require('fs');try{const c=JSON.parse(fs.readFileSync('$CONFIG_PATH','utf8'));console.log((c.enforcement||'enabled').toLowerCase());}catch(e){console.log('enabled');}\")",
|
|
22
|
+
" if [ \"$ENFORCEMENT\" = \"disabled\" ]; then",
|
|
23
|
+
" echo \"CodeProof enforcement is temporarily disabled.\"",
|
|
24
|
+
" echo \"Commit allowed.\"",
|
|
25
|
+
" exit 0",
|
|
26
|
+
" fi",
|
|
27
|
+
"fi",
|
|
28
|
+
"CODEPROOF_PRECOMMIT=1 codeproof run --precommit",
|
|
16
29
|
"RESULT=$?",
|
|
17
30
|
"if [ $RESULT -ne 0 ]; then",
|
|
18
31
|
" echo \"CodeProof checks failed. Commit blocked.\"",
|
|
@@ -36,7 +49,20 @@ export function installPreCommitHook(gitRoot) {
|
|
|
36
49
|
"#!/bin/sh",
|
|
37
50
|
"",
|
|
38
51
|
"# Auto-generated by CodeProof",
|
|
39
|
-
"
|
|
52
|
+
"GIT_ROOT=$(git rev-parse --show-toplevel 2>/dev/null)",
|
|
53
|
+
"if [ -n \"$GIT_ROOT\" ]; then",
|
|
54
|
+
" cd \"$GIT_ROOT\" || exit 1",
|
|
55
|
+
"fi",
|
|
56
|
+
"CONFIG_PATH=\"$GIT_ROOT/codeproof.config.json\"",
|
|
57
|
+
"if [ -f \"$CONFIG_PATH\" ]; then",
|
|
58
|
+
" ENFORCEMENT=$(node -e \"const fs=require('fs');try{const c=JSON.parse(fs.readFileSync('$CONFIG_PATH','utf8'));console.log((c.enforcement||'enabled').toLowerCase());}catch(e){console.log('enabled');}\")",
|
|
59
|
+
" if [ \"$ENFORCEMENT\" = \"disabled\" ]; then",
|
|
60
|
+
" echo \"CodeProof enforcement is temporarily disabled.\"",
|
|
61
|
+
" echo \"Commit allowed.\"",
|
|
62
|
+
" exit 0",
|
|
63
|
+
" fi",
|
|
64
|
+
"fi",
|
|
65
|
+
"CODEPROOF_PRECOMMIT=1 codeproof run --precommit",
|
|
40
66
|
"RESULT=$?",
|
|
41
67
|
"if [ $RESULT -ne 0 ]; then",
|
|
42
68
|
" echo \"CodeProof checks failed. Commit blocked.\"",
|