@neurcode-ai/cli 0.9.43 → 0.9.45
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/dist/commands/check.js +20 -2
- package/dist/commands/contract.js +47 -0
- package/dist/commands/plan.js +40 -0
- package/dist/commands/verify.d.ts +2 -0
- package/dist/commands/verify.js +294 -136
- package/dist/config.d.ts +13 -0
- package/dist/config.js +48 -0
- package/dist/index.js +41 -5
- package/dist/utils/advisory-signals.d.ts +20 -0
- package/dist/utils/advisory-signals.js +177 -0
- package/dist/utils/artifact-signature.js +21 -0
- package/dist/utils/change-contract.d.ts +105 -1
- package/dist/utils/change-contract.js +685 -12
- package/dist/utils/diff-symbols.d.ts +10 -0
- package/dist/utils/diff-symbols.js +218 -0
- package/dist/utils/plan-symbols.d.ts +17 -0
- package/dist/utils/plan-symbols.js +209 -0
- package/package.json +2 -11
- package/dist/api-client.d.ts.map +0 -1
- package/dist/api-client.js.map +0 -1
- package/dist/commands/allow.d.ts.map +0 -1
- package/dist/commands/allow.js.map +0 -1
- package/dist/commands/apply.d.ts.map +0 -1
- package/dist/commands/apply.js.map +0 -1
- package/dist/commands/approve.d.ts.map +0 -1
- package/dist/commands/approve.js.map +0 -1
- package/dist/commands/ask.d.ts.map +0 -1
- package/dist/commands/ask.js.map +0 -1
- package/dist/commands/audit.d.ts.map +0 -1
- package/dist/commands/audit.js.map +0 -1
- package/dist/commands/bootstrap.d.ts.map +0 -1
- package/dist/commands/bootstrap.js.map +0 -1
- package/dist/commands/brain.d.ts.map +0 -1
- package/dist/commands/brain.js.map +0 -1
- package/dist/commands/check.d.ts.map +0 -1
- package/dist/commands/check.js.map +0 -1
- package/dist/commands/config.d.ts.map +0 -1
- package/dist/commands/config.js.map +0 -1
- package/dist/commands/contract.d.ts.map +0 -1
- package/dist/commands/contract.js.map +0 -1
- package/dist/commands/doctor.d.ts.map +0 -1
- package/dist/commands/doctor.js.map +0 -1
- package/dist/commands/feedback.d.ts.map +0 -1
- package/dist/commands/feedback.js.map +0 -1
- package/dist/commands/guard.d.ts.map +0 -1
- package/dist/commands/guard.js.map +0 -1
- package/dist/commands/init.d.ts.map +0 -1
- package/dist/commands/init.js.map +0 -1
- package/dist/commands/login.d.ts.map +0 -1
- package/dist/commands/login.js.map +0 -1
- package/dist/commands/logout.d.ts.map +0 -1
- package/dist/commands/logout.js.map +0 -1
- package/dist/commands/map.d.ts.map +0 -1
- package/dist/commands/map.js.map +0 -1
- package/dist/commands/plan-slo.d.ts.map +0 -1
- package/dist/commands/plan-slo.js.map +0 -1
- package/dist/commands/plan.d.ts.map +0 -1
- package/dist/commands/plan.js.map +0 -1
- package/dist/commands/policy.d.ts.map +0 -1
- package/dist/commands/policy.js.map +0 -1
- package/dist/commands/prompt.d.ts.map +0 -1
- package/dist/commands/prompt.js.map +0 -1
- package/dist/commands/refactor.d.ts.map +0 -1
- package/dist/commands/refactor.js.map +0 -1
- package/dist/commands/remediate.d.ts.map +0 -1
- package/dist/commands/remediate.js.map +0 -1
- package/dist/commands/repo.d.ts.map +0 -1
- package/dist/commands/repo.js.map +0 -1
- package/dist/commands/revert.d.ts.map +0 -1
- package/dist/commands/revert.js.map +0 -1
- package/dist/commands/security.d.ts.map +0 -1
- package/dist/commands/security.js.map +0 -1
- package/dist/commands/session.d.ts.map +0 -1
- package/dist/commands/session.js.map +0 -1
- package/dist/commands/ship.d.ts.map +0 -1
- package/dist/commands/ship.js.map +0 -1
- package/dist/commands/simulate.d.ts.map +0 -1
- package/dist/commands/simulate.js.map +0 -1
- package/dist/commands/verify.d.ts.map +0 -1
- package/dist/commands/verify.js.map +0 -1
- package/dist/commands/watch.d.ts.map +0 -1
- package/dist/commands/watch.js.map +0 -1
- package/dist/commands/whoami.d.ts.map +0 -1
- package/dist/commands/whoami.js.map +0 -1
- package/dist/config.d.ts.map +0 -1
- package/dist/config.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/rules.d.ts.map +0 -1
- package/dist/rules.js.map +0 -1
- package/dist/services/integrations/TicketService.d.ts.map +0 -1
- package/dist/services/integrations/TicketService.js.map +0 -1
- package/dist/services/mapper/ProjectScanner.d.ts.map +0 -1
- package/dist/services/mapper/ProjectScanner.js.map +0 -1
- package/dist/services/project-knowledge-service.d.ts.map +0 -1
- package/dist/services/project-knowledge-service.js.map +0 -1
- package/dist/services/security/SecurityGuard.d.ts.map +0 -1
- package/dist/services/security/SecurityGuard.js.map +0 -1
- package/dist/services/toolbox-service.d.ts.map +0 -1
- package/dist/services/toolbox-service.js.map +0 -1
- package/dist/services/watch/BlobStore.d.ts.map +0 -1
- package/dist/services/watch/BlobStore.js.map +0 -1
- package/dist/services/watch/CommandPoller.d.ts.map +0 -1
- package/dist/services/watch/CommandPoller.js.map +0 -1
- package/dist/services/watch/Journal.d.ts.map +0 -1
- package/dist/services/watch/Journal.js.map +0 -1
- package/dist/services/watch/Sentinel.d.ts.map +0 -1
- package/dist/services/watch/Sentinel.js.map +0 -1
- package/dist/services/watch/Syncer.d.ts.map +0 -1
- package/dist/services/watch/Syncer.js.map +0 -1
- package/dist/utils/ROILogger.d.ts.map +0 -1
- package/dist/utils/ROILogger.js.map +0 -1
- package/dist/utils/RelevanceScorer.d.ts.map +0 -1
- package/dist/utils/RelevanceScorer.js.map +0 -1
- package/dist/utils/ai-debt-budget.d.ts.map +0 -1
- package/dist/utils/ai-debt-budget.js.map +0 -1
- package/dist/utils/artifact-signature.d.ts.map +0 -1
- package/dist/utils/artifact-signature.js.map +0 -1
- package/dist/utils/ask-cache.d.ts.map +0 -1
- package/dist/utils/ask-cache.js.map +0 -1
- package/dist/utils/box.d.ts.map +0 -1
- package/dist/utils/box.js.map +0 -1
- package/dist/utils/brain-context.d.ts.map +0 -1
- package/dist/utils/brain-context.js.map +0 -1
- package/dist/utils/breakage-simulator.d.ts.map +0 -1
- package/dist/utils/breakage-simulator.js.map +0 -1
- package/dist/utils/change-contract.d.ts.map +0 -1
- package/dist/utils/change-contract.js.map +0 -1
- package/dist/utils/cli-json.d.ts.map +0 -1
- package/dist/utils/cli-json.js.map +0 -1
- package/dist/utils/custom-policy-rules.d.ts.map +0 -1
- package/dist/utils/custom-policy-rules.js.map +0 -1
- package/dist/utils/git.d.ts.map +0 -1
- package/dist/utils/git.js.map +0 -1
- package/dist/utils/gitignore.d.ts.map +0 -1
- package/dist/utils/gitignore.js.map +0 -1
- package/dist/utils/governance.d.ts.map +0 -1
- package/dist/utils/governance.js.map +0 -1
- package/dist/utils/ignore.d.ts.map +0 -1
- package/dist/utils/ignore.js.map +0 -1
- package/dist/utils/manual-approvals.d.ts.map +0 -1
- package/dist/utils/manual-approvals.js.map +0 -1
- package/dist/utils/messages.d.ts.map +0 -1
- package/dist/utils/messages.js.map +0 -1
- package/dist/utils/neurcode-context.d.ts.map +0 -1
- package/dist/utils/neurcode-context.js.map +0 -1
- package/dist/utils/plan-cache.d.ts.map +0 -1
- package/dist/utils/plan-cache.js.map +0 -1
- package/dist/utils/plan-slo.d.ts.map +0 -1
- package/dist/utils/plan-slo.js.map +0 -1
- package/dist/utils/policy-audit.d.ts.map +0 -1
- package/dist/utils/policy-audit.js.map +0 -1
- package/dist/utils/policy-compiler.d.ts.map +0 -1
- package/dist/utils/policy-compiler.js.map +0 -1
- package/dist/utils/policy-exceptions.d.ts.map +0 -1
- package/dist/utils/policy-exceptions.js.map +0 -1
- package/dist/utils/policy-governance.d.ts.map +0 -1
- package/dist/utils/policy-governance.js.map +0 -1
- package/dist/utils/policy-packs.d.ts.map +0 -1
- package/dist/utils/policy-packs.js.map +0 -1
- package/dist/utils/project-detector.d.ts.map +0 -1
- package/dist/utils/project-detector.js.map +0 -1
- package/dist/utils/project-root.d.ts.map +0 -1
- package/dist/utils/project-root.js.map +0 -1
- package/dist/utils/repo-links.d.ts.map +0 -1
- package/dist/utils/repo-links.js.map +0 -1
- package/dist/utils/restore.d.ts.map +0 -1
- package/dist/utils/restore.js.map +0 -1
- package/dist/utils/runtime-guard.d.ts.map +0 -1
- package/dist/utils/runtime-guard.js.map +0 -1
- package/dist/utils/scope-telemetry.d.ts.map +0 -1
- package/dist/utils/scope-telemetry.js.map +0 -1
- package/dist/utils/secret-masking.d.ts.map +0 -1
- package/dist/utils/secret-masking.js.map +0 -1
- package/dist/utils/state.d.ts.map +0 -1
- package/dist/utils/state.js.map +0 -1
- package/dist/utils/tier.d.ts.map +0 -1
- package/dist/utils/tier.js.map +0 -1
- package/dist/utils/user-context.d.ts.map +0 -1
- package/dist/utils/user-context.js.map +0 -1
package/dist/commands/verify.js
CHANGED
|
@@ -51,7 +51,6 @@ const path_1 = require("path");
|
|
|
51
51
|
const fs_1 = require("fs");
|
|
52
52
|
const state_1 = require("../utils/state");
|
|
53
53
|
const ROILogger_1 = require("../utils/ROILogger");
|
|
54
|
-
const box_1 = require("../utils/box");
|
|
55
54
|
const ignore_1 = require("../utils/ignore");
|
|
56
55
|
const project_root_1 = require("../utils/project-root");
|
|
57
56
|
const brain_context_1 = require("../utils/brain-context");
|
|
@@ -64,6 +63,8 @@ const policy_audit_1 = require("../utils/policy-audit");
|
|
|
64
63
|
const governance_1 = require("../utils/governance");
|
|
65
64
|
const policy_compiler_1 = require("../utils/policy-compiler");
|
|
66
65
|
const change_contract_1 = require("../utils/change-contract");
|
|
66
|
+
const diff_symbols_1 = require("../utils/diff-symbols");
|
|
67
|
+
const advisory_signals_1 = require("../utils/advisory-signals");
|
|
67
68
|
const runtime_guard_1 = require("../utils/runtime-guard");
|
|
68
69
|
const artifact_signature_1 = require("../utils/artifact-signature");
|
|
69
70
|
const policy_1 = require("@neurcode-ai/policy");
|
|
@@ -796,31 +797,29 @@ function parseSigningKeyRing(raw) {
|
|
|
796
797
|
return out;
|
|
797
798
|
}
|
|
798
799
|
function resolveGovernanceSigningConfig() {
|
|
799
|
-
const
|
|
800
|
-
const envSigningKey = process.env.NEURCODE_GOVERNANCE_SIGNING_KEY?.trim() ||
|
|
801
|
-
process.env.NEURCODE_AI_LOG_SIGNING_KEY?.trim() ||
|
|
802
|
-
'';
|
|
803
|
-
const requestedKeyId = process.env.NEURCODE_GOVERNANCE_SIGNING_KEY_ID?.trim() || '';
|
|
800
|
+
const artifactSigningConfig = (0, artifact_signature_1.resolveGovernanceArtifactSigningConfigFromEnv)();
|
|
804
801
|
const signer = process.env.NEURCODE_GOVERNANCE_SIGNER || process.env.USER || 'neurcode-cli';
|
|
805
|
-
let signingKey = envSigningKey || null;
|
|
806
|
-
let signingKeyId = requestedKeyId || null;
|
|
807
|
-
if (!signingKey && Object.keys(signingKeys).length > 0) {
|
|
808
|
-
if (signingKeyId && signingKeys[signingKeyId]) {
|
|
809
|
-
signingKey = signingKeys[signingKeyId];
|
|
810
|
-
}
|
|
811
|
-
else {
|
|
812
|
-
const fallbackKeyId = Object.keys(signingKeys).sort((a, b) => a.localeCompare(b))[0];
|
|
813
|
-
signingKey = signingKeys[fallbackKeyId];
|
|
814
|
-
signingKeyId = signingKeyId || fallbackKeyId;
|
|
815
|
-
}
|
|
816
|
-
}
|
|
817
802
|
return {
|
|
818
|
-
signingKey,
|
|
819
|
-
signingKeyId,
|
|
820
|
-
signingKeys,
|
|
803
|
+
signingKey: artifactSigningConfig.signingKey,
|
|
804
|
+
signingKeyId: artifactSigningConfig.signingKeyId,
|
|
805
|
+
signingKeys: artifactSigningConfig.signingKeys,
|
|
821
806
|
signer,
|
|
822
807
|
};
|
|
823
808
|
}
|
|
809
|
+
function isGitRepository(cwd) {
|
|
810
|
+
try {
|
|
811
|
+
const output = (0, child_process_1.execSync)('git rev-parse --is-inside-work-tree', {
|
|
812
|
+
cwd,
|
|
813
|
+
encoding: 'utf-8',
|
|
814
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
815
|
+
maxBuffer: 1024 * 1024,
|
|
816
|
+
}).trim().toLowerCase();
|
|
817
|
+
return output === 'true';
|
|
818
|
+
}
|
|
819
|
+
catch {
|
|
820
|
+
return false;
|
|
821
|
+
}
|
|
822
|
+
}
|
|
824
823
|
function isSignedAiLogsRequired(orgGovernanceSettings) {
|
|
825
824
|
return (orgGovernanceSettings?.requireSignedAiLogs === true ||
|
|
826
825
|
isEnabledFlag(process.env.NEURCODE_GOVERNANCE_REQUIRE_SIGNED_LOGS) ||
|
|
@@ -1525,6 +1524,40 @@ async function verifyCommand(options) {
|
|
|
1525
1524
|
};
|
|
1526
1525
|
console.log(JSON.stringify(jsonPayload, null, 2));
|
|
1527
1526
|
};
|
|
1527
|
+
if (!isGitRepository(projectRoot)) {
|
|
1528
|
+
const message = 'Verify requires a git repository. Initialize git (`git init`) or run this command inside an existing git project.';
|
|
1529
|
+
if (options.json) {
|
|
1530
|
+
emitVerifyJson({
|
|
1531
|
+
grade: 'F',
|
|
1532
|
+
score: 0,
|
|
1533
|
+
verdict: 'FAIL',
|
|
1534
|
+
violations: [
|
|
1535
|
+
{
|
|
1536
|
+
file: '.',
|
|
1537
|
+
rule: 'git_repository_required',
|
|
1538
|
+
severity: 'block',
|
|
1539
|
+
message,
|
|
1540
|
+
},
|
|
1541
|
+
],
|
|
1542
|
+
adherenceScore: 0,
|
|
1543
|
+
bloatCount: 0,
|
|
1544
|
+
bloatFiles: [],
|
|
1545
|
+
plannedFilesModified: 0,
|
|
1546
|
+
totalPlannedFiles: 0,
|
|
1547
|
+
message,
|
|
1548
|
+
scopeGuardPassed: false,
|
|
1549
|
+
mode: 'git_repository_required',
|
|
1550
|
+
policyOnly: options.policyOnly === true,
|
|
1551
|
+
});
|
|
1552
|
+
}
|
|
1553
|
+
else {
|
|
1554
|
+
console.log(chalk.red('\n❌ Git Repository Required'));
|
|
1555
|
+
console.log(chalk.red(` ${message}`));
|
|
1556
|
+
console.log(chalk.dim(` Current path: ${projectRoot}`));
|
|
1557
|
+
console.log(chalk.dim(' Next step: git init && git add . && git commit -m "chore: baseline"\n'));
|
|
1558
|
+
}
|
|
1559
|
+
process.exit(1);
|
|
1560
|
+
}
|
|
1528
1561
|
const enforceChangeContract = options.enforceChangeContract === true ||
|
|
1529
1562
|
isEnabledFlag(process.env.NEURCODE_VERIFY_ENFORCE_CHANGE_CONTRACT);
|
|
1530
1563
|
const explicitStrictArtifactMode = options.strictArtifacts === true ||
|
|
@@ -1972,7 +2005,7 @@ async function verifyCommand(options) {
|
|
|
1972
2005
|
// Determine which diff to capture (staged + unstaged for full current work)
|
|
1973
2006
|
let diffText;
|
|
1974
2007
|
if (options.staged) {
|
|
1975
|
-
diffText = (0, child_process_1.execSync)('git diff --
|
|
2008
|
+
diffText = (0, child_process_1.execSync)('git diff --cached', { maxBuffer: 1024 * 1024 * 1024, encoding: 'utf-8' });
|
|
1976
2009
|
}
|
|
1977
2010
|
else if (options.base) {
|
|
1978
2011
|
diffText = (0, git_1.getDiffFromBase)(options.base);
|
|
@@ -1983,7 +2016,7 @@ async function verifyCommand(options) {
|
|
|
1983
2016
|
else {
|
|
1984
2017
|
// Default: combine staged + unstaged to capture all current work
|
|
1985
2018
|
try {
|
|
1986
|
-
const stagedDiff = (0, child_process_1.execSync)('git diff --
|
|
2019
|
+
const stagedDiff = (0, child_process_1.execSync)('git diff --cached', { maxBuffer: 1024 * 1024 * 1024, encoding: 'utf-8' });
|
|
1987
2020
|
const unstagedDiff = (0, child_process_1.execSync)('git diff', { maxBuffer: 1024 * 1024 * 1024, encoding: 'utf-8' });
|
|
1988
2021
|
diffText = stagedDiff + (stagedDiff && unstagedDiff ? '\n' : '') + unstagedDiff;
|
|
1989
2022
|
}
|
|
@@ -2276,6 +2309,9 @@ async function verifyCommand(options) {
|
|
|
2276
2309
|
console.log(chalk.cyan('\n📊 Analyzing changes against plan...'));
|
|
2277
2310
|
console.log(chalk.dim(` Found ${summary.totalFiles} file(s) changed`));
|
|
2278
2311
|
console.log(chalk.dim(` ${summary.totalAdded} lines added, ${summary.totalRemoved} lines removed\n`));
|
|
2312
|
+
if (options.demo) {
|
|
2313
|
+
console.log(chalk.dim(' Demo mode enabled: showing extra context while keeping drift output short and grouped.\n'));
|
|
2314
|
+
}
|
|
2279
2315
|
}
|
|
2280
2316
|
const runPolicyOnlyModeAndExit = async (source) => {
|
|
2281
2317
|
const exitCode = await executePolicyOnlyMode(options, diffFiles, shouldIgnore, projectRoot, config, client, source, scopeTelemetry, projectId || undefined, orgGovernanceSettings, aiLogSigningKey, aiLogSigningKeyId, aiLogSigningKeys, aiLogSigner, compiledPolicyMetadata, changeContractSummary);
|
|
@@ -2368,10 +2404,104 @@ async function verifyCommand(options) {
|
|
|
2368
2404
|
});
|
|
2369
2405
|
process.exit(1);
|
|
2370
2406
|
}
|
|
2371
|
-
|
|
2372
|
-
|
|
2407
|
+
let autoContractPath = null;
|
|
2408
|
+
if (!changeContractRead.contract && !strictArtifactMode) {
|
|
2409
|
+
try {
|
|
2410
|
+
const fallbackPlanId = `advisory_${Date.now()}`;
|
|
2411
|
+
const advisoryContract = buildMinimalAdvisoryContractFromDiff(diffFiles, fallbackPlanId);
|
|
2412
|
+
autoContractPath = (0, change_contract_1.writeChangeContract)(projectRoot, advisoryContract, options.changeContract);
|
|
2413
|
+
changeContractSummary = {
|
|
2414
|
+
path: autoContractPath,
|
|
2415
|
+
exists: true,
|
|
2416
|
+
enforced: false,
|
|
2417
|
+
valid: true,
|
|
2418
|
+
planId: advisoryContract.planId,
|
|
2419
|
+
contractId: advisoryContract.contractId,
|
|
2420
|
+
coverage: {
|
|
2421
|
+
expectedFiles: advisoryContract.expectedFiles.length,
|
|
2422
|
+
changedFiles: diffFiles.length,
|
|
2423
|
+
outOfContractFiles: 0,
|
|
2424
|
+
missingExpectedFiles: 0,
|
|
2425
|
+
blockedFilesTouched: 0,
|
|
2426
|
+
actionMismatches: 0,
|
|
2427
|
+
expectedSymbols: advisoryContract.expectedSymbols?.length || 0,
|
|
2428
|
+
changedSymbols: 0,
|
|
2429
|
+
missingExpectedSymbols: 0,
|
|
2430
|
+
blockedSymbolsTouched: 0,
|
|
2431
|
+
symbolActionMismatches: 0,
|
|
2432
|
+
symbolRenameMatches: 0,
|
|
2433
|
+
toleratedUnexpectedFiles: 0,
|
|
2434
|
+
toleratedMissingExpectedSymbols: 0,
|
|
2435
|
+
},
|
|
2436
|
+
signature: changeContractSummary.signature,
|
|
2437
|
+
violations: [],
|
|
2438
|
+
};
|
|
2439
|
+
}
|
|
2440
|
+
catch {
|
|
2441
|
+
autoContractPath = null;
|
|
2442
|
+
}
|
|
2443
|
+
}
|
|
2444
|
+
const message = 'No plan linked yet. Ran advisory verification for quick first-run experience. ' +
|
|
2445
|
+
'Use `neurcode plan` and `neurcode contract import --auto-detect --write-change-contract` for full enforcement.';
|
|
2446
|
+
const advisorySignals = (0, advisory_signals_1.evaluateAdvisorySignals)({
|
|
2447
|
+
diffFiles,
|
|
2448
|
+
summary,
|
|
2449
|
+
});
|
|
2450
|
+
const advisoryWarnCount = advisorySignals.filter((item) => item.severity === 'warn').length;
|
|
2451
|
+
const advisoryVerdict = advisoryWarnCount > 0 ? 'WARN' : 'PASS';
|
|
2452
|
+
const advisoryGrade = advisoryWarnCount > 0 ? 'C' : 'B';
|
|
2453
|
+
const advisoryScore = advisoryWarnCount > 0 ? 60 : 70;
|
|
2454
|
+
const advisoryViolations = advisorySignals.map((item) => ({
|
|
2455
|
+
file: item.files[0] || '.',
|
|
2456
|
+
rule: `advisory:${item.code.toLowerCase()}`,
|
|
2457
|
+
severity: item.severity === 'warn' ? 'warn' : 'allow',
|
|
2458
|
+
message: `${item.title}: ${item.detail}`,
|
|
2459
|
+
}));
|
|
2460
|
+
recordVerifyEvent(advisoryVerdict, `advisory_missing_plan;signals=${advisorySignals.length};warn=${advisoryWarnCount}`, diffFiles.map((f) => f.path));
|
|
2461
|
+
if (options.json) {
|
|
2462
|
+
emitVerifyJson({
|
|
2463
|
+
grade: advisoryGrade,
|
|
2464
|
+
score: advisoryScore,
|
|
2465
|
+
verdict: advisoryVerdict,
|
|
2466
|
+
violations: advisoryViolations,
|
|
2467
|
+
adherenceScore: advisoryScore,
|
|
2468
|
+
bloatCount: 0,
|
|
2469
|
+
bloatFiles: [],
|
|
2470
|
+
plannedFilesModified: 0,
|
|
2471
|
+
totalPlannedFiles: 0,
|
|
2472
|
+
message,
|
|
2473
|
+
scopeGuardPassed: true,
|
|
2474
|
+
mode: 'advisory_missing_plan',
|
|
2475
|
+
advisoryMode: true,
|
|
2476
|
+
advisorySignals,
|
|
2477
|
+
policyOnly: true,
|
|
2478
|
+
policyOnlySource: 'fallback_missing_plan',
|
|
2479
|
+
...(autoContractPath
|
|
2480
|
+
? {
|
|
2481
|
+
changeContract: {
|
|
2482
|
+
...changeContractSummary,
|
|
2483
|
+
path: autoContractPath,
|
|
2484
|
+
},
|
|
2485
|
+
}
|
|
2486
|
+
: {
|
|
2487
|
+
changeContract: changeContractSummary,
|
|
2488
|
+
}),
|
|
2489
|
+
});
|
|
2373
2490
|
}
|
|
2374
|
-
|
|
2491
|
+
else {
|
|
2492
|
+
printFirstRunAdvisoryMessage(options.demo === true);
|
|
2493
|
+
printAdvisorySignals(advisorySignals, options.demo === true);
|
|
2494
|
+
if (autoContractPath) {
|
|
2495
|
+
console.log(chalk.green(`✅ Auto-generated minimal advisory contract: ${autoContractPath}`));
|
|
2496
|
+
}
|
|
2497
|
+
else if (!changeContractRead.contract) {
|
|
2498
|
+
console.log(chalk.yellow('⚠️ Could not auto-generate advisory contract; continuing without contract.'));
|
|
2499
|
+
}
|
|
2500
|
+
console.log(chalk.dim('Next steps: neurcode plan "<intent>"'));
|
|
2501
|
+
console.log(chalk.dim(' neurcode contract import --auto-detect --write-change-contract'));
|
|
2502
|
+
console.log(chalk.dim(`\nSummary: ${message}\n`));
|
|
2503
|
+
}
|
|
2504
|
+
process.exit(0);
|
|
2375
2505
|
}
|
|
2376
2506
|
if (!planId) {
|
|
2377
2507
|
throw new Error('Plan ID resolution failed unexpectedly');
|
|
@@ -2965,6 +3095,7 @@ async function verifyCommand(options) {
|
|
|
2965
3095
|
})),
|
|
2966
3096
|
})),
|
|
2967
3097
|
}));
|
|
3098
|
+
const changedSymbols = (0, diff_symbols_1.extractDeclaredSymbolsFromDiff)(diffFiles);
|
|
2968
3099
|
const compiledIntentProof = (0, governance_runtime_1.compileDeterministicConstraints)({
|
|
2969
3100
|
intentConstraints: intentConstraintsForVerification,
|
|
2970
3101
|
policyRules: deterministicPolicyRules,
|
|
@@ -3036,6 +3167,16 @@ async function verifyCommand(options) {
|
|
|
3036
3167
|
? (0, change_contract_1.evaluateChangeContract)(changeContractRead.contract, {
|
|
3037
3168
|
planId: finalPlanId,
|
|
3038
3169
|
changedFiles: changedFiles.map((file) => file.path),
|
|
3170
|
+
changedFileEntries: changedFiles.map((file) => ({
|
|
3171
|
+
path: file.path,
|
|
3172
|
+
changeType: file.changeType,
|
|
3173
|
+
})),
|
|
3174
|
+
changedSymbols: changedSymbols.map((symbol) => ({
|
|
3175
|
+
name: symbol.name,
|
|
3176
|
+
type: symbol.type,
|
|
3177
|
+
action: symbol.action,
|
|
3178
|
+
file: symbol.file,
|
|
3179
|
+
})),
|
|
3039
3180
|
policyLockFingerprint: (0, policy_packs_1.readPolicyLockFile)(projectRoot).lock?.effective.fingerprint || null,
|
|
3040
3181
|
compiledPolicyFingerprint: effectiveCompiledPolicy?.fingerprint || null,
|
|
3041
3182
|
})
|
|
@@ -3054,6 +3195,8 @@ async function verifyCommand(options) {
|
|
|
3054
3195
|
code: item.code,
|
|
3055
3196
|
message: item.message,
|
|
3056
3197
|
file: item.file,
|
|
3198
|
+
symbol: item.symbol,
|
|
3199
|
+
symbolType: item.symbolType,
|
|
3057
3200
|
expected: item.expected,
|
|
3058
3201
|
actual: item.actual,
|
|
3059
3202
|
})),
|
|
@@ -3065,9 +3208,8 @@ async function verifyCommand(options) {
|
|
|
3065
3208
|
severity: 'block',
|
|
3066
3209
|
message: item.message,
|
|
3067
3210
|
}));
|
|
3068
|
-
const message = `
|
|
3069
|
-
.
|
|
3070
|
-
.join('; ')}`;
|
|
3211
|
+
const message = `Implementation deviates from intended contract (` +
|
|
3212
|
+
`${changeContractEvaluation.violations.length} violation(s)).`;
|
|
3071
3213
|
if (options.json) {
|
|
3072
3214
|
emitVerifyJson({
|
|
3073
3215
|
grade: 'F',
|
|
@@ -3088,11 +3230,7 @@ async function verifyCommand(options) {
|
|
|
3088
3230
|
});
|
|
3089
3231
|
}
|
|
3090
3232
|
else {
|
|
3091
|
-
|
|
3092
|
-
changeContractEvaluation.violations.forEach((item) => {
|
|
3093
|
-
console.log(chalk.red(` • ${item.message}`));
|
|
3094
|
-
});
|
|
3095
|
-
console.log(chalk.dim(` Contract path: ${changeContractRead.path}`));
|
|
3233
|
+
displayChangeContractDrift(changeContractSummary, { advisory: false });
|
|
3096
3234
|
}
|
|
3097
3235
|
await recordVerificationIfRequested(options, config, {
|
|
3098
3236
|
grade: 'F',
|
|
@@ -3116,13 +3254,7 @@ async function verifyCommand(options) {
|
|
|
3116
3254
|
process.exit(2);
|
|
3117
3255
|
}
|
|
3118
3256
|
else if (!changeContractEvaluation.valid && !options.json) {
|
|
3119
|
-
|
|
3120
|
-
changeContractEvaluation.violations.slice(0, 5).forEach((item) => {
|
|
3121
|
-
console.log(chalk.yellow(` • ${item.message}`));
|
|
3122
|
-
});
|
|
3123
|
-
if (changeContractEvaluation.violations.length > 5) {
|
|
3124
|
-
console.log(chalk.dim(` ... ${changeContractEvaluation.violations.length - 5} more violation(s)`));
|
|
3125
|
-
}
|
|
3257
|
+
displayChangeContractDrift(changeContractSummary, { advisory: true });
|
|
3126
3258
|
}
|
|
3127
3259
|
}
|
|
3128
3260
|
// Call verify API
|
|
@@ -3880,111 +4012,137 @@ function displayGovernanceInsights(governance, options = {}) {
|
|
|
3880
4012
|
});
|
|
3881
4013
|
}
|
|
3882
4014
|
}
|
|
4015
|
+
function displayChangeContractDrift(summary, options = { advisory: false }) {
|
|
4016
|
+
const groups = (0, change_contract_1.groupChangeContractViolations)(summary.violations.map((item) => ({
|
|
4017
|
+
code: item.code,
|
|
4018
|
+
message: item.message,
|
|
4019
|
+
...(item.file ? { file: item.file } : {}),
|
|
4020
|
+
...(item.symbol ? { symbol: item.symbol } : {}),
|
|
4021
|
+
...(item.symbolType ? { symbolType: item.symbolType } : {}),
|
|
4022
|
+
...(item.expected ? { expected: item.expected } : {}),
|
|
4023
|
+
...(item.actual ? { actual: item.actual } : {}),
|
|
4024
|
+
})));
|
|
4025
|
+
if (groups.length === 0)
|
|
4026
|
+
return;
|
|
4027
|
+
const maxItemsPerGroup = options.maxItemsPerGroup ?? 12;
|
|
4028
|
+
const header = options.advisory
|
|
4029
|
+
? chalk.yellow('\nWARN ⚠️ Change contract drift detected')
|
|
4030
|
+
: chalk.red('\nFAIL ❌ Change contract enforcement failed');
|
|
4031
|
+
console.log(header);
|
|
4032
|
+
for (const group of groups) {
|
|
4033
|
+
console.log(chalk.white(`\n${group.title}:`));
|
|
4034
|
+
group.items.slice(0, maxItemsPerGroup).forEach((entry) => {
|
|
4035
|
+
console.log(` - ${entry}`);
|
|
4036
|
+
});
|
|
4037
|
+
if (group.items.length > maxItemsPerGroup) {
|
|
4038
|
+
console.log(chalk.dim(` - ... ${group.items.length - maxItemsPerGroup} more`));
|
|
4039
|
+
}
|
|
4040
|
+
console.log(chalk.dim(` Why it matters: ${group.impact}`));
|
|
4041
|
+
}
|
|
4042
|
+
console.log(chalk.dim('\nSummary:'));
|
|
4043
|
+
console.log(chalk.dim('Implementation deviates from intended contract.'));
|
|
4044
|
+
console.log(chalk.dim(`Contract path: ${summary.path}`));
|
|
4045
|
+
}
|
|
3883
4046
|
/**
|
|
3884
4047
|
* Display verification results in a formatted report card
|
|
3885
4048
|
*/
|
|
3886
4049
|
function displayVerifyResults(result, policyViolations) {
|
|
3887
|
-
|
|
3888
|
-
|
|
3889
|
-
|
|
3890
|
-
|
|
3891
|
-
|
|
3892
|
-
|
|
3893
|
-
|
|
3894
|
-
|
|
3895
|
-
|
|
3896
|
-
|
|
3897
|
-
|
|
3898
|
-
|
|
3899
|
-
|
|
3900
|
-
|
|
3901
|
-
|
|
3902
|
-
|
|
3903
|
-
|
|
3904
|
-
// Bloat drops grade by one letter (B -> C, C -> D, D -> F)
|
|
3905
|
-
if (result.bloatCount > 0) {
|
|
3906
|
-
if (baseGrade === 'B')
|
|
3907
|
-
baseGrade = 'C';
|
|
3908
|
-
else if (baseGrade === 'C')
|
|
3909
|
-
baseGrade = 'D';
|
|
3910
|
-
else if (baseGrade === 'D')
|
|
3911
|
-
baseGrade = 'F';
|
|
3912
|
-
}
|
|
3913
|
-
grade = baseGrade;
|
|
3914
|
-
gradeColor = chalk.yellow;
|
|
3915
|
-
}
|
|
3916
|
-
else {
|
|
3917
|
-
grade = 'F';
|
|
3918
|
-
gradeColor = chalk.red;
|
|
3919
|
-
}
|
|
3920
|
-
// Calculate estimated time saved (5 minutes per VERIFY_PASS)
|
|
3921
|
-
const estimatedMinutesSaved = result.verdict === 'PASS' ? 5 : 0;
|
|
3922
|
-
// Calculate policy compliance percentage
|
|
3923
|
-
const policyCompliance = result.bloatCount === 0 ? 100 : Math.max(0, 100 - (result.bloatCount * 10));
|
|
3924
|
-
// Display Governance Badge for PASS and FAIL verdicts (high visibility)
|
|
3925
|
-
if (result.verdict === 'PASS' || result.verdict === 'FAIL') {
|
|
3926
|
-
console.log('\n');
|
|
3927
|
-
const borderColor = result.verdict === 'PASS' ? 'green' : 'red';
|
|
3928
|
-
const gradeColorFunc = result.verdict === 'PASS' ? chalk.green.bold : chalk.red.bold;
|
|
3929
|
-
const badgeContent = [
|
|
3930
|
-
`${chalk.bold.white('Governance Badge')}`,
|
|
3931
|
-
'',
|
|
3932
|
-
`${chalk.cyan('Grade:')} ${gradeColorFunc(grade)} ${chalk.dim(`(${result.adherenceScore}%)`)}`,
|
|
3933
|
-
result.verdict === 'PASS' ? `${chalk.cyan('Estimated Time Saved:')} ${chalk.green.bold(`${estimatedMinutesSaved}m`)}` : '',
|
|
3934
|
-
`${chalk.cyan('Policy Compliance:')} ${result.verdict === 'PASS' ? chalk.green.bold(`${policyCompliance}%`) : chalk.red.bold(`${policyCompliance}%`)}`,
|
|
3935
|
-
].filter(line => line !== '').join('\n');
|
|
3936
|
-
console.log((0, box_1.createBox)(badgeContent, {
|
|
3937
|
-
borderColor,
|
|
3938
|
-
titleColor: 'white',
|
|
3939
|
-
padding: 2,
|
|
3940
|
-
}));
|
|
3941
|
-
console.log('');
|
|
3942
|
-
}
|
|
3943
|
-
console.log(chalk.bold.cyan('📋 Plan Adherence Report\n'));
|
|
3944
|
-
console.log('━'.repeat(50));
|
|
3945
|
-
const scoreDisplay = gradeColor(`Grade: ${grade} (${result.adherenceScore}%)`);
|
|
3946
|
-
if (result.verdict === 'PASS') {
|
|
3947
|
-
console.log(chalk.green('✅'), scoreDisplay);
|
|
4050
|
+
const verdictLabel = result.verdict === 'PASS'
|
|
4051
|
+
? chalk.green('PASS ✅')
|
|
4052
|
+
: result.verdict === 'WARN'
|
|
4053
|
+
? chalk.yellow('WARN ⚠️')
|
|
4054
|
+
: chalk.red('FAIL ❌');
|
|
4055
|
+
const plannedText = `${result.plannedFilesModified}/${result.totalPlannedFiles}`;
|
|
4056
|
+
console.log(`\n${verdictLabel}`);
|
|
4057
|
+
console.log(chalk.dim(`Plan adherence: ${plannedText} files (${result.adherenceScore}%)`));
|
|
4058
|
+
const maxItems = 20;
|
|
4059
|
+
if (result.bloatCount > 0) {
|
|
4060
|
+
console.log(chalk.red('\nOut-of-scope changes:'));
|
|
4061
|
+
result.bloatFiles.slice(0, maxItems).forEach((file) => {
|
|
4062
|
+
console.log(` - ${file}`);
|
|
4063
|
+
});
|
|
4064
|
+
if (result.bloatFiles.length > maxItems) {
|
|
4065
|
+
console.log(chalk.dim(` - ... ${result.bloatFiles.length - maxItems} more`));
|
|
4066
|
+
}
|
|
3948
4067
|
}
|
|
3949
|
-
|
|
3950
|
-
|
|
4068
|
+
if (policyViolations && policyViolations.length > 0) {
|
|
4069
|
+
const blocking = policyViolations.filter((item) => item.severity === 'block');
|
|
4070
|
+
const warnings = policyViolations.filter((item) => item.severity !== 'block');
|
|
4071
|
+
if (blocking.length > 0) {
|
|
4072
|
+
console.log(chalk.red('\nBlocking policy violations:'));
|
|
4073
|
+
blocking.slice(0, maxItems).forEach((item) => {
|
|
4074
|
+
console.log(` - ${item.file}: ${item.message || item.rule}`);
|
|
4075
|
+
});
|
|
4076
|
+
if (blocking.length > maxItems) {
|
|
4077
|
+
console.log(chalk.dim(` - ... ${blocking.length - maxItems} more`));
|
|
4078
|
+
}
|
|
4079
|
+
}
|
|
4080
|
+
if (warnings.length > 0) {
|
|
4081
|
+
console.log(chalk.yellow('\nPolicy warnings:'));
|
|
4082
|
+
warnings.slice(0, maxItems).forEach((item) => {
|
|
4083
|
+
console.log(` - ${item.file}: ${item.message || item.rule}`);
|
|
4084
|
+
});
|
|
4085
|
+
if (warnings.length > maxItems) {
|
|
4086
|
+
console.log(chalk.dim(` - ... ${warnings.length - maxItems} more`));
|
|
4087
|
+
}
|
|
4088
|
+
}
|
|
3951
4089
|
}
|
|
3952
|
-
|
|
3953
|
-
console.log(chalk.
|
|
4090
|
+
if (result.bloatCount === 0 && (!policyViolations || policyViolations.length === 0)) {
|
|
4091
|
+
console.log(chalk.green('\nNo drift detected.'));
|
|
3954
4092
|
}
|
|
3955
|
-
console.log(
|
|
3956
|
-
|
|
3957
|
-
|
|
3958
|
-
console.log(
|
|
3959
|
-
|
|
3960
|
-
|
|
3961
|
-
|
|
3962
|
-
|
|
3963
|
-
|
|
3964
|
-
|
|
3965
|
-
|
|
3966
|
-
});
|
|
4093
|
+
console.log(chalk.dim(`\nSummary: ${result.message}\n`));
|
|
4094
|
+
}
|
|
4095
|
+
function printFirstRunAdvisoryMessage(demoMode) {
|
|
4096
|
+
console.log(chalk.cyan('\nNeurcode first-run advisory mode'));
|
|
4097
|
+
console.log(chalk.dim('Neurcode checks if your AI-generated code matches your intended plan.'));
|
|
4098
|
+
console.log(chalk.dim('To get full enforcement:'));
|
|
4099
|
+
console.log(chalk.dim('1. Define a plan'));
|
|
4100
|
+
console.log(chalk.dim('2. Generate a contract'));
|
|
4101
|
+
console.log(chalk.dim('Running in advisory mode for now.\n'));
|
|
4102
|
+
if (demoMode) {
|
|
4103
|
+
console.log(chalk.dim('Demo mode: this run is intentionally non-blocking to make evaluation easy.'));
|
|
3967
4104
|
}
|
|
3968
|
-
|
|
3969
|
-
|
|
3970
|
-
|
|
4105
|
+
}
|
|
4106
|
+
function printAdvisorySignals(signals, demoMode) {
|
|
4107
|
+
if (signals.length === 0) {
|
|
4108
|
+
if (demoMode) {
|
|
4109
|
+
console.log(chalk.dim('No high-signal advisory findings detected for this diff.'));
|
|
4110
|
+
}
|
|
4111
|
+
return;
|
|
3971
4112
|
}
|
|
3972
|
-
|
|
3973
|
-
|
|
3974
|
-
|
|
3975
|
-
|
|
3976
|
-
|
|
3977
|
-
|
|
3978
|
-
|
|
3979
|
-
console.log(label);
|
|
3980
|
-
policyViolations.forEach(v => {
|
|
3981
|
-
const lineColor = v.severity === 'block' ? chalk.red : chalk.yellow;
|
|
3982
|
-
console.log(lineColor(` • ${v.file}: ${v.message || v.rule}`));
|
|
4113
|
+
console.log(chalk.yellow('\nAdvisory findings (non-blocking):'));
|
|
4114
|
+
for (const signal of signals) {
|
|
4115
|
+
const severityLabel = signal.severity === 'warn' ? chalk.yellow('[warn]') : chalk.dim('[info]');
|
|
4116
|
+
console.log(`${severityLabel} ${signal.title}`);
|
|
4117
|
+
console.log(chalk.dim(` ${signal.detail}`));
|
|
4118
|
+
signal.files.forEach((file) => {
|
|
4119
|
+
console.log(chalk.dim(` - ${file}`));
|
|
3983
4120
|
});
|
|
3984
4121
|
}
|
|
3985
|
-
|
|
3986
|
-
|
|
3987
|
-
|
|
3988
|
-
|
|
4122
|
+
}
|
|
4123
|
+
function buildMinimalAdvisoryContractFromDiff(diffFiles, fallbackPlanId) {
|
|
4124
|
+
const expectedFiles = [...new Set(diffFiles.map((file) => toUnixPath(file.path)).filter(Boolean))];
|
|
4125
|
+
const planFiles = expectedFiles.map((path) => {
|
|
4126
|
+
const entry = diffFiles.find((file) => toUnixPath(file.path) === path);
|
|
4127
|
+
const changeType = entry?.changeType;
|
|
4128
|
+
const action = changeType === 'add' ? 'CREATE' : 'MODIFY';
|
|
4129
|
+
return {
|
|
4130
|
+
path,
|
|
4131
|
+
action: action,
|
|
4132
|
+
reason: 'Auto-generated advisory baseline from current diff',
|
|
4133
|
+
};
|
|
4134
|
+
});
|
|
4135
|
+
return (0, change_contract_1.createChangeContract)({
|
|
4136
|
+
planId: fallbackPlanId,
|
|
4137
|
+
intent: 'Advisory baseline generated from current repository diff',
|
|
4138
|
+
expectedFiles,
|
|
4139
|
+
planFiles,
|
|
4140
|
+
options: {
|
|
4141
|
+
enforceExpectedFiles: false,
|
|
4142
|
+
enforceActionMatching: false,
|
|
4143
|
+
enforceExpectedSymbols: false,
|
|
4144
|
+
enforceSymbolActionMatching: false,
|
|
4145
|
+
},
|
|
4146
|
+
});
|
|
3989
4147
|
}
|
|
3990
4148
|
//# sourceMappingURL=verify.js.map
|
package/dist/config.d.ts
CHANGED
|
@@ -10,6 +10,19 @@ export interface NeurcodeConfig {
|
|
|
10
10
|
projectId?: string;
|
|
11
11
|
orgId?: string;
|
|
12
12
|
}
|
|
13
|
+
export interface LocalGovernanceSigningMaterial {
|
|
14
|
+
signingKey: string;
|
|
15
|
+
signingKeyId: string;
|
|
16
|
+
source: 'persisted' | 'generated';
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Resolve a local governance signing key from ~/.neurcoderc.
|
|
20
|
+
* If authenticated and no key exists, auto-provision one for smoother
|
|
21
|
+
* login-first onboarding in orgs that require signed AI logs.
|
|
22
|
+
*/
|
|
23
|
+
export declare function getOrCreateLocalGovernanceSigningMaterial(options?: {
|
|
24
|
+
autoProvision?: boolean;
|
|
25
|
+
}): LocalGovernanceSigningMaterial | null;
|
|
13
26
|
export declare function loadConfig(): NeurcodeConfig;
|
|
14
27
|
/**
|
|
15
28
|
* Get API key with helpful error message if not found
|
package/dist/config.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.DEFAULT_API_URL = void 0;
|
|
4
|
+
exports.getOrCreateLocalGovernanceSigningMaterial = getOrCreateLocalGovernanceSigningMaterial;
|
|
4
5
|
exports.loadConfig = loadConfig;
|
|
5
6
|
exports.getApiKey = getApiKey;
|
|
6
7
|
exports.requireApiKey = requireApiKey;
|
|
@@ -10,6 +11,7 @@ exports.deleteGlobalAuth = deleteGlobalAuth;
|
|
|
10
11
|
exports.deleteApiKeyFromAllSources = deleteApiKeyFromAllSources;
|
|
11
12
|
const fs_1 = require("fs");
|
|
12
13
|
const path_1 = require("path");
|
|
14
|
+
const crypto_1 = require("crypto");
|
|
13
15
|
const state_1 = require("./utils/state");
|
|
14
16
|
const project_root_1 = require("./utils/project-root");
|
|
15
17
|
/**
|
|
@@ -93,6 +95,52 @@ function writeGlobalAuthFile(data) {
|
|
|
93
95
|
// Ignore
|
|
94
96
|
}
|
|
95
97
|
}
|
|
98
|
+
/**
|
|
99
|
+
* Resolve a local governance signing key from ~/.neurcoderc.
|
|
100
|
+
* If authenticated and no key exists, auto-provision one for smoother
|
|
101
|
+
* login-first onboarding in orgs that require signed AI logs.
|
|
102
|
+
*/
|
|
103
|
+
function getOrCreateLocalGovernanceSigningMaterial(options) {
|
|
104
|
+
const autoProvision = options?.autoProvision !== false;
|
|
105
|
+
const global = readGlobalAuthFile();
|
|
106
|
+
if (!global)
|
|
107
|
+
return null;
|
|
108
|
+
const cfg = global.data || {};
|
|
109
|
+
const persistedKey = typeof cfg.governanceSigningKey === 'string'
|
|
110
|
+
? cfg.governanceSigningKey.trim()
|
|
111
|
+
: '';
|
|
112
|
+
let persistedKeyId = typeof cfg.governanceSigningKeyId === 'string'
|
|
113
|
+
? cfg.governanceSigningKeyId.trim()
|
|
114
|
+
: '';
|
|
115
|
+
if (persistedKey) {
|
|
116
|
+
if (!persistedKeyId) {
|
|
117
|
+
persistedKeyId = `local-${Date.now().toString(36)}`;
|
|
118
|
+
cfg.governanceSigningKeyId = persistedKeyId;
|
|
119
|
+
writeGlobalAuthFile(cfg);
|
|
120
|
+
}
|
|
121
|
+
return {
|
|
122
|
+
signingKey: persistedKey,
|
|
123
|
+
signingKeyId: persistedKeyId,
|
|
124
|
+
source: 'persisted',
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
if (!autoProvision)
|
|
128
|
+
return null;
|
|
129
|
+
const hasApiAuthMaterial = Boolean((cfg.apiKey || '').trim())
|
|
130
|
+
|| Object.keys(cfg.apiKeysByOrg || {}).length > 0;
|
|
131
|
+
if (!hasApiAuthMaterial)
|
|
132
|
+
return null;
|
|
133
|
+
const signingKey = (0, crypto_1.randomBytes)(32).toString('hex');
|
|
134
|
+
const signingKeyId = `local-${Date.now().toString(36)}`;
|
|
135
|
+
cfg.governanceSigningKey = signingKey;
|
|
136
|
+
cfg.governanceSigningKeyId = signingKeyId;
|
|
137
|
+
writeGlobalAuthFile(cfg);
|
|
138
|
+
return {
|
|
139
|
+
signingKey,
|
|
140
|
+
signingKeyId,
|
|
141
|
+
source: 'generated',
|
|
142
|
+
};
|
|
143
|
+
}
|
|
96
144
|
function pickApiKeyFromKeyring(globalCfg, desiredOrgId) {
|
|
97
145
|
const keyring = globalCfg.apiKeysByOrg || {};
|
|
98
146
|
if (desiredOrgId) {
|