@neurcode-ai/cli 0.9.45 → 0.9.47

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/README.md CHANGED
@@ -49,14 +49,17 @@ neurcode brain mode --storage-mode no-code
49
49
  neurcode brain doctor "is userid used instead of org id"
50
50
  ```
51
51
 
52
- ## Enterprise Governance Signing
52
+ ## Enterprise Governance Signing (Optional Hardening)
53
53
 
54
54
  Use signed AI change logs for fail-closed governance in `verify`/`ship`.
55
55
 
56
56
  ```bash
57
- # Mandatory signed logs (fail closed when key material is missing)
57
+ # Optional strict mode: require signed logs (fail closed when key material is missing)
58
58
  export NEURCODE_GOVERNANCE_REQUIRE_SIGNED_LOGS=1
59
59
 
60
+ # Optional: honor org-level signed log requirement from control plane
61
+ export NEURCODE_GOVERNANCE_ENFORCE_ORG_SIGNED_LOG_REQUIREMENT=1
62
+
60
63
  # Single-key mode
61
64
  export NEURCODE_GOVERNANCE_SIGNING_KEY="<strong-random-secret>"
62
65
  export NEURCODE_GOVERNANCE_SIGNING_KEY_ID="kid-prod-2026-03"
@@ -68,10 +71,11 @@ export NEURCODE_GOVERNANCE_SIGNING_KEY_ID="kid-prod-2026-03"
68
71
 
69
72
  Notes:
70
73
  - `verify` writes and verifies `.neurcode/ai-change-log.json` with integrity chain checks.
71
- - If signed logs are required and integrity/signature checks fail, `verify` exits non-zero.
74
+ - If strict signed-log mode is enabled and integrity/signature checks fail, `verify` exits non-zero.
72
75
  - `ship` will block deployment when required signed AI logs are missing/invalid.
73
76
  - `policy compile` and `plan` auto-sign deterministic artifacts when governance signing keys are configured.
74
77
  - Use `--require-signed-artifacts` (or `NEURCODE_VERIFY_REQUIRE_SIGNED_ARTIFACTS=1`) to fail closed on unsigned/tampered artifacts.
78
+ - Default onboarding flow is non-blocking unless strict signing is explicitly enabled.
75
79
 
76
80
  ## Docs
77
81
 
@@ -825,6 +825,15 @@ function isEnabledFlag(value) {
825
825
  const normalized = value.trim().toLowerCase();
826
826
  return normalized === '1' || normalized === 'true' || normalized === 'yes' || normalized === 'on';
827
827
  }
828
+ function isSignedAiLogsRequired(orgGovernance) {
829
+ const explicitRequirement = isEnabledFlag(process.env.NEURCODE_GOVERNANCE_REQUIRE_SIGNED_LOGS) ||
830
+ isEnabledFlag(process.env.NEURCODE_AI_LOG_REQUIRE_SIGNED);
831
+ if (explicitRequirement) {
832
+ return true;
833
+ }
834
+ const honorOrgRequirement = isEnabledFlag(process.env.NEURCODE_GOVERNANCE_ENFORCE_ORG_SIGNED_LOG_REQUIREMENT);
835
+ return honorOrgRequirement && orgGovernance?.requireSignedAiLogs === true;
836
+ }
828
837
  function collectApplyWrittenFiles(output) {
829
838
  const clean = stripAnsi(output);
830
839
  const files = [];
@@ -1846,9 +1855,7 @@ async function shipCommand(goal, options) {
1846
1855
  const manualApprovalBypass = options.manualApproveHighRisk === true || process.env.NEURCODE_MANUAL_APPROVE_HIGH_RISK === '1';
1847
1856
  const governanceDecision = finalVerifyPayload.governanceDecision?.decision;
1848
1857
  const orgGovernance = finalVerifyPayload.orgGovernance || null;
1849
- const signedAiLogsRequired = orgGovernance?.requireSignedAiLogs === true ||
1850
- isEnabledFlag(process.env.NEURCODE_GOVERNANCE_REQUIRE_SIGNED_LOGS) ||
1851
- isEnabledFlag(process.env.NEURCODE_AI_LOG_REQUIRE_SIGNED);
1858
+ const signedAiLogsRequired = isSignedAiLogsRequired(orgGovernance);
1852
1859
  const aiLogIntegrity = finalVerifyPayload.aiChangeLog?.integrity;
1853
1860
  const signedAiLogsValid = aiLogIntegrity?.valid === true && aiLogIntegrity?.signed === true;
1854
1861
  const orgManualApprovalRequired = orgGovernance?.requireManualApproval === true;
@@ -101,9 +101,9 @@ function toArtifactSignatureSummary(status) {
101
101
  };
102
102
  }
103
103
  function resolveCliComponentVersion() {
104
- const fromEnv = process.env.NEURCODE_CLI_VERSION || process.env.npm_package_version;
105
- if (fromEnv && fromEnv.trim()) {
106
- return fromEnv.trim();
104
+ const explicitEnvVersion = process.env.NEURCODE_CLI_VERSION;
105
+ if (explicitEnvVersion && explicitEnvVersion.trim()) {
106
+ return explicitEnvVersion.trim();
107
107
  }
108
108
  try {
109
109
  const packagePath = (0, path_1.join)(__dirname, '../../package.json');
@@ -116,6 +116,12 @@ function resolveCliComponentVersion() {
116
116
  catch {
117
117
  // Ignore and fall back.
118
118
  }
119
+ const npmContextVersion = process.env.npm_package_version;
120
+ if (npmContextVersion
121
+ && npmContextVersion.trim()
122
+ && npmContextVersion.trim() !== '0.0.0') {
123
+ return npmContextVersion.trim();
124
+ }
119
125
  return '0.0.0';
120
126
  }
121
127
  const CLI_COMPONENT_VERSION = resolveCliComponentVersion();
@@ -821,9 +827,13 @@ function isGitRepository(cwd) {
821
827
  }
822
828
  }
823
829
  function isSignedAiLogsRequired(orgGovernanceSettings) {
824
- return (orgGovernanceSettings?.requireSignedAiLogs === true ||
825
- isEnabledFlag(process.env.NEURCODE_GOVERNANCE_REQUIRE_SIGNED_LOGS) ||
826
- isEnabledFlag(process.env.NEURCODE_AI_LOG_REQUIRE_SIGNED));
830
+ const explicitRequirement = isEnabledFlag(process.env.NEURCODE_GOVERNANCE_REQUIRE_SIGNED_LOGS) ||
831
+ isEnabledFlag(process.env.NEURCODE_AI_LOG_REQUIRE_SIGNED);
832
+ if (explicitRequirement) {
833
+ return true;
834
+ }
835
+ const honorOrgRequirement = isEnabledFlag(process.env.NEURCODE_GOVERNANCE_ENFORCE_ORG_SIGNED_LOG_REQUIREMENT);
836
+ return honorOrgRequirement && orgGovernanceSettings?.requireSignedAiLogs === true;
827
837
  }
828
838
  function policyLockMismatchMessage(mismatches) {
829
839
  if (mismatches.length === 0) {
@@ -1012,6 +1022,7 @@ async function executePolicyOnlyMode(options, diffFiles, ignoreFilter, projectRo
1012
1022
  if (!options.json) {
1013
1023
  console.log(chalk.cyan('🛡️ General Governance mode (policy only, no plan linked)\n'));
1014
1024
  }
1025
+ const signedLogsRequired = isSignedAiLogsRequired(orgGovernanceSettings);
1015
1026
  const governanceAnalysis = (0, governance_1.evaluateGovernance)({
1016
1027
  projectRoot,
1017
1028
  task: 'Policy-only verification',
@@ -1019,6 +1030,7 @@ async function executePolicyOnlyMode(options, diffFiles, ignoreFilter, projectRo
1019
1030
  diffFiles,
1020
1031
  contextCandidates: diffFiles.map((file) => file.path),
1021
1032
  orgGovernance: orgGovernanceSettings,
1033
+ requireSignedAiLogs: signedLogsRequired,
1022
1034
  signingKey: aiLogSigningKey,
1023
1035
  signingKeyId: aiLogSigningKeyId,
1024
1036
  signingKeys: aiLogSigningKeys,
@@ -1029,7 +1041,6 @@ async function executePolicyOnlyMode(options, diffFiles, ignoreFilter, projectRo
1029
1041
  changeContract: changeContractSummary,
1030
1042
  });
1031
1043
  const contextPolicyViolations = governanceAnalysis.contextPolicy.violations.filter((item) => !ignoreFilter(item.file));
1032
- const signedLogsRequired = isSignedAiLogsRequired(orgGovernanceSettings);
1033
1044
  if (signedLogsRequired && !governanceAnalysis.aiChangeLogIntegrity.valid) {
1034
1045
  const message = `AI change-log integrity check failed: ${governanceAnalysis.aiChangeLogIntegrity.issues.join('; ') || 'unknown issue'}`;
1035
1046
  if (options.json) {
@@ -2246,6 +2257,7 @@ async function verifyCommand(options) {
2246
2257
  diffFiles,
2247
2258
  contextCandidates: diffFiles.map((file) => file.path),
2248
2259
  orgGovernance: orgGovernanceSettings,
2260
+ requireSignedAiLogs: signedLogsRequired,
2249
2261
  signingKey: aiLogSigningKey,
2250
2262
  signingKeyId: aiLogSigningKeyId,
2251
2263
  signingKeys: aiLogSigningKeys,
@@ -2547,6 +2559,7 @@ async function verifyCommand(options) {
2547
2559
  diffFiles,
2548
2560
  contextCandidates: planFiles,
2549
2561
  orgGovernance: orgGovernanceSettings,
2562
+ requireSignedAiLogs: signedLogsRequired,
2550
2563
  signingKey: aiLogSigningKey,
2551
2564
  signingKeyId: aiLogSigningKeyId,
2552
2565
  signingKeys: aiLogSigningKeys,
@@ -8,6 +8,7 @@ export interface GovernanceEvaluationInput {
8
8
  diffFiles: DiffFile[];
9
9
  contextCandidates?: string[];
10
10
  orgGovernance?: OrgGovernanceSettings | null;
11
+ requireSignedAiLogs?: boolean;
11
12
  signingKey?: string | null;
12
13
  signingKeyId?: string | null;
13
14
  signingKeys?: Record<string, string> | null;
@@ -35,7 +35,7 @@ function evaluateGovernance(input) {
35
35
  });
36
36
  let aiChangeLogIntegrity = writtenChangeLog.integrity;
37
37
  let governanceDecisionFinal = governanceDecision;
38
- const requireSignedAiLogs = input.orgGovernance?.requireSignedAiLogs === true;
38
+ const requireSignedAiLogs = input.requireSignedAiLogs === true;
39
39
  if (requireSignedAiLogs) {
40
40
  aiChangeLogIntegrity = (0, analysis_1.verifyAiChangeLogIntegrity)(input.projectRoot, {
41
41
  requiredSigned: true,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@neurcode-ai/cli",
3
- "version": "0.9.45",
3
+ "version": "0.9.47",
4
4
  "description": "Neurcode CLI - AI code governance and diff analysis",
5
5
  "bin": {
6
6
  "neurcode": "dist/index.js"