@neurcode/action 0.2.1 → 0.2.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/README.md +9 -3
- package/action.yml +36 -4
- package/dist/index.js +618 -9
- package/dist/index.js.map +1 -1
- package/dist/runtime-compat.js +125 -0
- package/dist/runtime-compat.js.map +1 -0
- package/dist/verify-mode.js +15 -0
- package/dist/verify-mode.js.map +1 -1
- package/package.json +9 -8
- package/src/index.ts +400 -9
- package/src/runtime-compat.ts +201 -0
- package/src/verify-mode.ts +32 -0
- package/tests/reliability-contract.test.ts +136 -0
- package/LICENSE +0 -201
package/dist/index.js
CHANGED
|
@@ -35282,7 +35282,13 @@ function wrappy (fn, cb) {
|
|
|
35282
35282
|
"use strict";
|
|
35283
35283
|
|
|
35284
35284
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
35285
|
-
exports.CLI_JSON_CONTRACT_VERSION = void 0;
|
|
35285
|
+
exports.RUNTIME_COMPATIBILITY_CONTRACT_VERSION = exports.RUNTIME_COMPATIBILITY_CONTRACT_ID = exports.CLI_JSON_CONTRACT_VERSION = void 0;
|
|
35286
|
+
exports.compareSemver = compareSemver;
|
|
35287
|
+
exports.isSemverAtLeast = isSemverAtLeast;
|
|
35288
|
+
exports.getMinimumCompatiblePeerVersion = getMinimumCompatiblePeerVersion;
|
|
35289
|
+
exports.getRuntimeMinimumPeerVersionMatrix = getRuntimeMinimumPeerVersionMatrix;
|
|
35290
|
+
exports.buildRuntimeCompatibilityDescriptor = buildRuntimeCompatibilityDescriptor;
|
|
35291
|
+
exports.evaluateRuntimePeerCompatibility = evaluateRuntimePeerCompatibility;
|
|
35286
35292
|
exports.parseCliPlanJsonPayload = parseCliPlanJsonPayload;
|
|
35287
35293
|
exports.parseCliApplyJsonPayload = parseCliApplyJsonPayload;
|
|
35288
35294
|
exports.parseCliVerifyJsonPayload = parseCliVerifyJsonPayload;
|
|
@@ -35291,7 +35297,24 @@ exports.parseCliShipJsonPayload = parseCliShipJsonPayload;
|
|
|
35291
35297
|
exports.parseCliShipRunsJsonPayload = parseCliShipRunsJsonPayload;
|
|
35292
35298
|
exports.parseCliShipResumeJsonPayload = parseCliShipResumeJsonPayload;
|
|
35293
35299
|
exports.parseCliShipAttestationVerifyJsonPayload = parseCliShipAttestationVerifyJsonPayload;
|
|
35300
|
+
exports.parseCliCompatJsonPayload = parseCliCompatJsonPayload;
|
|
35294
35301
|
exports.CLI_JSON_CONTRACT_VERSION = '2026-04-04';
|
|
35302
|
+
exports.RUNTIME_COMPATIBILITY_CONTRACT_ID = 'neurcode-runtime-compatibility';
|
|
35303
|
+
exports.RUNTIME_COMPATIBILITY_CONTRACT_VERSION = '2026-04-04';
|
|
35304
|
+
const RUNTIME_MINIMUM_PEER_VERSIONS = {
|
|
35305
|
+
cli: {
|
|
35306
|
+
action: '0.2.1',
|
|
35307
|
+
api: '0.2.0',
|
|
35308
|
+
},
|
|
35309
|
+
action: {
|
|
35310
|
+
cli: '0.9.35',
|
|
35311
|
+
api: '0.2.0',
|
|
35312
|
+
},
|
|
35313
|
+
api: {
|
|
35314
|
+
cli: '0.9.35',
|
|
35315
|
+
action: '0.2.1',
|
|
35316
|
+
},
|
|
35317
|
+
};
|
|
35295
35318
|
function asRecord(value, label) {
|
|
35296
35319
|
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
35297
35320
|
throw new Error(`${label}: expected object`);
|
|
@@ -35347,6 +35370,125 @@ function asContractVersion(record) {
|
|
|
35347
35370
|
}
|
|
35348
35371
|
return value;
|
|
35349
35372
|
}
|
|
35373
|
+
function asRuntimeComponent(record, key, label) {
|
|
35374
|
+
const value = asString(record, key, label);
|
|
35375
|
+
if (value === 'cli' || value === 'action' || value === 'api') {
|
|
35376
|
+
return value;
|
|
35377
|
+
}
|
|
35378
|
+
throw new Error(`${label}: expected ${key}:("cli"|"action"|"api")`);
|
|
35379
|
+
}
|
|
35380
|
+
function parseRuntimeMinimumPeerVersions(value, label) {
|
|
35381
|
+
if (value === undefined || value === null)
|
|
35382
|
+
return {};
|
|
35383
|
+
const record = asRecord(value, `${label}.minimumPeerVersions`);
|
|
35384
|
+
const next = {};
|
|
35385
|
+
for (const component of ['cli', 'action', 'api']) {
|
|
35386
|
+
const componentValue = record[component];
|
|
35387
|
+
if (componentValue === undefined)
|
|
35388
|
+
continue;
|
|
35389
|
+
if (typeof componentValue !== 'string' || !componentValue.trim()) {
|
|
35390
|
+
throw new Error(`${label}.minimumPeerVersions: expected ${component}:string`);
|
|
35391
|
+
}
|
|
35392
|
+
next[component] = componentValue.trim();
|
|
35393
|
+
}
|
|
35394
|
+
return next;
|
|
35395
|
+
}
|
|
35396
|
+
function parseRuntimeCompatibilityDescriptor(value, label) {
|
|
35397
|
+
const record = asRecord(value, `${label}.compatibility`);
|
|
35398
|
+
return {
|
|
35399
|
+
contractId: asString(record, 'contractId', `${label}.compatibility`),
|
|
35400
|
+
runtimeContractVersion: asString(record, 'runtimeContractVersion', `${label}.compatibility`),
|
|
35401
|
+
cliJsonContractVersion: asString(record, 'cliJsonContractVersion', `${label}.compatibility`),
|
|
35402
|
+
component: asRuntimeComponent(record, 'component', `${label}.compatibility`),
|
|
35403
|
+
componentVersion: asString(record, 'componentVersion', `${label}.compatibility`),
|
|
35404
|
+
minimumPeerVersions: parseRuntimeMinimumPeerVersions(record.minimumPeerVersions, `${label}.compatibility`),
|
|
35405
|
+
};
|
|
35406
|
+
}
|
|
35407
|
+
function parseSemver(value) {
|
|
35408
|
+
const normalized = value.trim().replace(/^v/i, '').split('+')[0].split('-')[0];
|
|
35409
|
+
const match = normalized.match(/^(\d+)\.(\d+)\.(\d+)$/);
|
|
35410
|
+
if (!match)
|
|
35411
|
+
return null;
|
|
35412
|
+
const major = Number(match[1]);
|
|
35413
|
+
const minor = Number(match[2]);
|
|
35414
|
+
const patch = Number(match[3]);
|
|
35415
|
+
if (!Number.isFinite(major) || !Number.isFinite(minor) || !Number.isFinite(patch)) {
|
|
35416
|
+
return null;
|
|
35417
|
+
}
|
|
35418
|
+
return [major, minor, patch];
|
|
35419
|
+
}
|
|
35420
|
+
function compareSemver(left, right) {
|
|
35421
|
+
const l = parseSemver(left);
|
|
35422
|
+
const r = parseSemver(right);
|
|
35423
|
+
if (!l || !r)
|
|
35424
|
+
return null;
|
|
35425
|
+
for (let idx = 0; idx < 3; idx += 1) {
|
|
35426
|
+
if (l[idx] > r[idx])
|
|
35427
|
+
return 1;
|
|
35428
|
+
if (l[idx] < r[idx])
|
|
35429
|
+
return -1;
|
|
35430
|
+
}
|
|
35431
|
+
return 0;
|
|
35432
|
+
}
|
|
35433
|
+
function isSemverAtLeast(actual, minimum) {
|
|
35434
|
+
const compare = compareSemver(actual, minimum);
|
|
35435
|
+
if (compare === null)
|
|
35436
|
+
return null;
|
|
35437
|
+
return compare >= 0;
|
|
35438
|
+
}
|
|
35439
|
+
function getMinimumCompatiblePeerVersion(component, peer) {
|
|
35440
|
+
return RUNTIME_MINIMUM_PEER_VERSIONS[component][peer];
|
|
35441
|
+
}
|
|
35442
|
+
function getRuntimeMinimumPeerVersionMatrix() {
|
|
35443
|
+
return {
|
|
35444
|
+
cli: { ...RUNTIME_MINIMUM_PEER_VERSIONS.cli },
|
|
35445
|
+
action: { ...RUNTIME_MINIMUM_PEER_VERSIONS.action },
|
|
35446
|
+
api: { ...RUNTIME_MINIMUM_PEER_VERSIONS.api },
|
|
35447
|
+
};
|
|
35448
|
+
}
|
|
35449
|
+
function buildRuntimeCompatibilityDescriptor(component, componentVersion) {
|
|
35450
|
+
return {
|
|
35451
|
+
contractId: exports.RUNTIME_COMPATIBILITY_CONTRACT_ID,
|
|
35452
|
+
runtimeContractVersion: exports.RUNTIME_COMPATIBILITY_CONTRACT_VERSION,
|
|
35453
|
+
cliJsonContractVersion: exports.CLI_JSON_CONTRACT_VERSION,
|
|
35454
|
+
component,
|
|
35455
|
+
componentVersion,
|
|
35456
|
+
minimumPeerVersions: { ...RUNTIME_MINIMUM_PEER_VERSIONS[component] },
|
|
35457
|
+
};
|
|
35458
|
+
}
|
|
35459
|
+
function evaluateRuntimePeerCompatibility(versions) {
|
|
35460
|
+
const issues = [];
|
|
35461
|
+
for (const component of ['cli', 'action', 'api']) {
|
|
35462
|
+
for (const peer of ['cli', 'action', 'api']) {
|
|
35463
|
+
if (peer === component)
|
|
35464
|
+
continue;
|
|
35465
|
+
const required = getMinimumCompatiblePeerVersion(component, peer);
|
|
35466
|
+
if (!required)
|
|
35467
|
+
continue;
|
|
35468
|
+
const actual = versions[peer];
|
|
35469
|
+
const compatible = isSemverAtLeast(actual, required);
|
|
35470
|
+
if (compatible === null) {
|
|
35471
|
+
issues.push({
|
|
35472
|
+
component,
|
|
35473
|
+
peer,
|
|
35474
|
+
required,
|
|
35475
|
+
actual,
|
|
35476
|
+
code: 'UNPARSABLE_VERSION',
|
|
35477
|
+
});
|
|
35478
|
+
}
|
|
35479
|
+
else if (!compatible) {
|
|
35480
|
+
issues.push({
|
|
35481
|
+
component,
|
|
35482
|
+
peer,
|
|
35483
|
+
required,
|
|
35484
|
+
actual,
|
|
35485
|
+
code: 'VERSION_BELOW_MINIMUM',
|
|
35486
|
+
});
|
|
35487
|
+
}
|
|
35488
|
+
}
|
|
35489
|
+
}
|
|
35490
|
+
return issues;
|
|
35491
|
+
}
|
|
35350
35492
|
function parseCliPlanJsonPayload(value, label = 'plan') {
|
|
35351
35493
|
const record = asRecord(value, label);
|
|
35352
35494
|
return {
|
|
@@ -35446,6 +35588,22 @@ function parseCliShipAttestationVerifyJsonPayload(value, label = 'ship-attestati
|
|
|
35446
35588
|
digest: asOptionalRecord(record, 'digest', label),
|
|
35447
35589
|
};
|
|
35448
35590
|
}
|
|
35591
|
+
function parseCliCompatJsonPayload(value, label = 'compat') {
|
|
35592
|
+
const record = asRecord(value, label);
|
|
35593
|
+
const component = asString(record, 'component', label);
|
|
35594
|
+
if (component !== 'cli') {
|
|
35595
|
+
throw new Error(`${label}: expected component:"cli"`);
|
|
35596
|
+
}
|
|
35597
|
+
return {
|
|
35598
|
+
...record,
|
|
35599
|
+
contractVersion: asContractVersion(record),
|
|
35600
|
+
success: asBoolean(record, 'success', label),
|
|
35601
|
+
timestamp: asString(record, 'timestamp', label),
|
|
35602
|
+
component: 'cli',
|
|
35603
|
+
componentVersion: asString(record, 'componentVersion', label),
|
|
35604
|
+
compatibility: parseRuntimeCompatibilityDescriptor(record.compatibility, label),
|
|
35605
|
+
};
|
|
35606
|
+
}
|
|
35449
35607
|
//# sourceMappingURL=index.js.map
|
|
35450
35608
|
|
|
35451
35609
|
/***/ }),
|
|
@@ -35494,8 +35652,11 @@ const exec = __importStar(__nccwpck_require__(7167));
|
|
|
35494
35652
|
const github = __importStar(__nccwpck_require__(5251));
|
|
35495
35653
|
const contracts_1 = __nccwpck_require__(7239);
|
|
35496
35654
|
const fs_1 = __nccwpck_require__(9896);
|
|
35655
|
+
const http = __importStar(__nccwpck_require__(8611));
|
|
35656
|
+
const https = __importStar(__nccwpck_require__(5692));
|
|
35497
35657
|
const path_1 = __nccwpck_require__(6928);
|
|
35498
35658
|
const verify_mode_1 = __nccwpck_require__(4288);
|
|
35659
|
+
const runtime_compat_1 = __nccwpck_require__(5654);
|
|
35499
35660
|
const ANSI_PATTERN = /\u001b\[[0-9;]*m/g;
|
|
35500
35661
|
const NON_FAST_FORWARD_PATTERNS = [
|
|
35501
35662
|
'non-fast-forward',
|
|
@@ -35543,6 +35704,17 @@ function parseBoolean(input, fallback) {
|
|
|
35543
35704
|
return false;
|
|
35544
35705
|
return fallback;
|
|
35545
35706
|
}
|
|
35707
|
+
function parseBooleanOrUndefined(input) {
|
|
35708
|
+
if (input === undefined || input === null || input.trim() === '') {
|
|
35709
|
+
return undefined;
|
|
35710
|
+
}
|
|
35711
|
+
const normalized = input.trim().toLowerCase();
|
|
35712
|
+
if (['1', 'true', 'yes', 'on'].includes(normalized))
|
|
35713
|
+
return true;
|
|
35714
|
+
if (['0', 'false', 'no', 'off'].includes(normalized))
|
|
35715
|
+
return false;
|
|
35716
|
+
return undefined;
|
|
35717
|
+
}
|
|
35546
35718
|
function parsePositiveInt(input, fallback, min, max) {
|
|
35547
35719
|
const parsed = Number(input);
|
|
35548
35720
|
if (!Number.isFinite(parsed))
|
|
@@ -35664,6 +35836,56 @@ function readJsonFile(path) {
|
|
|
35664
35836
|
return null;
|
|
35665
35837
|
}
|
|
35666
35838
|
}
|
|
35839
|
+
function assertStrictDeterministicArtifacts(input) {
|
|
35840
|
+
if (!input.strictMode)
|
|
35841
|
+
return;
|
|
35842
|
+
const errors = [];
|
|
35843
|
+
if (!input.supportsCompiledPolicy) {
|
|
35844
|
+
errors.push('Current CLI does not support --compiled-policy, but strict mode requires a compiled policy artifact.');
|
|
35845
|
+
}
|
|
35846
|
+
if (!input.supportsChangeContract) {
|
|
35847
|
+
errors.push('Current CLI does not support --change-contract, but strict mode requires a change contract artifact.');
|
|
35848
|
+
}
|
|
35849
|
+
const compiledPath = input.compiledPolicyPath?.trim();
|
|
35850
|
+
if (!compiledPath) {
|
|
35851
|
+
errors.push('Missing compiled policy artifact path in strict mode (compiled_policy_path).');
|
|
35852
|
+
}
|
|
35853
|
+
else {
|
|
35854
|
+
const absoluteCompiledPath = (0, path_1.resolve)(input.cwd, compiledPath);
|
|
35855
|
+
const compiled = readJsonFile(absoluteCompiledPath);
|
|
35856
|
+
if (!compiled) {
|
|
35857
|
+
errors.push(`Compiled policy artifact not found or invalid JSON: ${compiledPath}`);
|
|
35858
|
+
}
|
|
35859
|
+
else {
|
|
35860
|
+
const hasFingerprint = typeof compiled.fingerprint === 'string' && compiled.fingerprint.trim().length > 0;
|
|
35861
|
+
const hasRules = Array.isArray(compiled.rules) || Array.isArray(compiled.statements);
|
|
35862
|
+
if (!hasFingerprint && !hasRules) {
|
|
35863
|
+
errors.push(`Compiled policy artifact appears invalid (missing fingerprint/rules): ${compiledPath}`);
|
|
35864
|
+
}
|
|
35865
|
+
}
|
|
35866
|
+
}
|
|
35867
|
+
const contractPath = input.changeContractPath?.trim();
|
|
35868
|
+
if (!contractPath) {
|
|
35869
|
+
errors.push('Missing change contract artifact path in strict mode (change_contract_path).');
|
|
35870
|
+
}
|
|
35871
|
+
else {
|
|
35872
|
+
const absoluteContractPath = (0, path_1.resolve)(input.cwd, contractPath);
|
|
35873
|
+
const contract = readJsonFile(absoluteContractPath);
|
|
35874
|
+
if (!contract) {
|
|
35875
|
+
errors.push(`Change contract artifact not found or invalid JSON: ${contractPath}`);
|
|
35876
|
+
}
|
|
35877
|
+
else {
|
|
35878
|
+
const hasContractId = typeof contract.contractId === 'string' && contract.contractId.trim().length > 0;
|
|
35879
|
+
const hasPlanId = typeof contract.planId === 'string' && contract.planId.trim().length > 0;
|
|
35880
|
+
if (!hasContractId || !hasPlanId) {
|
|
35881
|
+
errors.push(`Change contract artifact appears invalid (missing contractId/planId): ${contractPath}`);
|
|
35882
|
+
}
|
|
35883
|
+
}
|
|
35884
|
+
}
|
|
35885
|
+
if (errors.length > 0) {
|
|
35886
|
+
throw new Error(`Strict enterprise mode requires deterministic compiled-policy + change-contract artifacts:\n- ${errors.join('\n- ')}`);
|
|
35887
|
+
}
|
|
35888
|
+
}
|
|
35667
35889
|
function detectProjectOrgId(cwd) {
|
|
35668
35890
|
const statePath = (0, path_1.join)(cwd, '.neurcode', 'config.json');
|
|
35669
35891
|
const state = readJsonFile(statePath);
|
|
@@ -35732,6 +35954,154 @@ function extractLastJsonObject(output) {
|
|
|
35732
35954
|
}
|
|
35733
35955
|
return null;
|
|
35734
35956
|
}
|
|
35957
|
+
function resolveActionPackageVersion() {
|
|
35958
|
+
const fromEnv = process.env.NEURCODE_ACTION_VERSION || process.env.npm_package_version;
|
|
35959
|
+
if (fromEnv && fromEnv.trim()) {
|
|
35960
|
+
return fromEnv.trim();
|
|
35961
|
+
}
|
|
35962
|
+
const candidates = [
|
|
35963
|
+
(0, path_1.resolve)(__dirname, '../package.json'),
|
|
35964
|
+
(0, path_1.resolve)(process.cwd(), 'package.json'),
|
|
35965
|
+
];
|
|
35966
|
+
for (const candidate of candidates) {
|
|
35967
|
+
try {
|
|
35968
|
+
if (!(0, fs_1.existsSync)(candidate))
|
|
35969
|
+
continue;
|
|
35970
|
+
const parsed = JSON.parse((0, fs_1.readFileSync)(candidate, 'utf-8'));
|
|
35971
|
+
const version = parsed?.version;
|
|
35972
|
+
if (typeof version === 'string' && version.trim()) {
|
|
35973
|
+
return version.trim();
|
|
35974
|
+
}
|
|
35975
|
+
}
|
|
35976
|
+
catch {
|
|
35977
|
+
// Ignore and continue to next candidate.
|
|
35978
|
+
}
|
|
35979
|
+
}
|
|
35980
|
+
return '0.0.0';
|
|
35981
|
+
}
|
|
35982
|
+
function normalizeApiBaseUrl(value) {
|
|
35983
|
+
return value.trim().replace(/\/+$/, '');
|
|
35984
|
+
}
|
|
35985
|
+
function requestJson(url, timeoutMs) {
|
|
35986
|
+
return new Promise((resolvePromise, rejectPromise) => {
|
|
35987
|
+
let target;
|
|
35988
|
+
try {
|
|
35989
|
+
target = new URL(url);
|
|
35990
|
+
}
|
|
35991
|
+
catch (error) {
|
|
35992
|
+
rejectPromise(new Error(`Invalid API URL: ${url} (${error instanceof Error ? error.message : String(error)})`));
|
|
35993
|
+
return;
|
|
35994
|
+
}
|
|
35995
|
+
const transport = target.protocol === 'http:' ? http : https;
|
|
35996
|
+
const request = transport.request({
|
|
35997
|
+
protocol: target.protocol,
|
|
35998
|
+
hostname: target.hostname,
|
|
35999
|
+
port: target.port || undefined,
|
|
36000
|
+
path: `${target.pathname}${target.search}`,
|
|
36001
|
+
method: 'GET',
|
|
36002
|
+
headers: {
|
|
36003
|
+
Accept: 'application/json',
|
|
36004
|
+
'User-Agent': 'neurcode-action/runtime-compat',
|
|
36005
|
+
},
|
|
36006
|
+
}, (response) => {
|
|
36007
|
+
let body = '';
|
|
36008
|
+
response.setEncoding('utf8');
|
|
36009
|
+
response.on('data', (chunk) => {
|
|
36010
|
+
body += chunk;
|
|
36011
|
+
});
|
|
36012
|
+
response.on('end', () => {
|
|
36013
|
+
let payload = null;
|
|
36014
|
+
try {
|
|
36015
|
+
payload = body ? JSON.parse(body) : null;
|
|
36016
|
+
}
|
|
36017
|
+
catch {
|
|
36018
|
+
payload = null;
|
|
36019
|
+
}
|
|
36020
|
+
resolvePromise({
|
|
36021
|
+
statusCode: response.statusCode || 0,
|
|
36022
|
+
body,
|
|
36023
|
+
payload,
|
|
36024
|
+
url,
|
|
36025
|
+
});
|
|
36026
|
+
});
|
|
36027
|
+
});
|
|
36028
|
+
request.on('error', (error) => {
|
|
36029
|
+
rejectPromise(new Error(`Request failed for ${url}: ${error.message}`));
|
|
36030
|
+
});
|
|
36031
|
+
request.setTimeout(timeoutMs, () => {
|
|
36032
|
+
request.destroy(new Error(`Request timed out after ${timeoutMs}ms`));
|
|
36033
|
+
});
|
|
36034
|
+
request.end();
|
|
36035
|
+
});
|
|
36036
|
+
}
|
|
36037
|
+
async function resolveApiHealthPayload(apiBaseUrl, timeoutMs) {
|
|
36038
|
+
const baseUrl = normalizeApiBaseUrl(apiBaseUrl);
|
|
36039
|
+
const candidates = [`${baseUrl}/api/v1/health`, `${baseUrl}/health`];
|
|
36040
|
+
const failures = [];
|
|
36041
|
+
for (const url of candidates) {
|
|
36042
|
+
try {
|
|
36043
|
+
const response = await requestJson(url, timeoutMs);
|
|
36044
|
+
const payload = response.payload;
|
|
36045
|
+
const statusValue = payload && typeof payload === 'object' && !Array.isArray(payload)
|
|
36046
|
+
? payload.status
|
|
36047
|
+
: null;
|
|
36048
|
+
if (response.statusCode >= 200 && response.statusCode < 300 && statusValue === 'ok') {
|
|
36049
|
+
return payload;
|
|
36050
|
+
}
|
|
36051
|
+
failures.push(`${url} returned ${response.statusCode}`);
|
|
36052
|
+
}
|
|
36053
|
+
catch (error) {
|
|
36054
|
+
failures.push(error instanceof Error ? error.message : String(error));
|
|
36055
|
+
}
|
|
36056
|
+
}
|
|
36057
|
+
throw new Error(`API compatibility probe failed (${failures.join(' | ')}).`);
|
|
36058
|
+
}
|
|
36059
|
+
async function runCompatibilityHandshake(input) {
|
|
36060
|
+
const actionVersion = resolveActionPackageVersion();
|
|
36061
|
+
const compatCommand = withCliCommandTimeout(input.cli, ['compat', '--json'], input.timeoutMinutes);
|
|
36062
|
+
const compatResult = await runCommand(compatCommand.cmd, compatCommand.args, { cwd: input.cwd });
|
|
36063
|
+
if (compatResult.exitCode !== 0) {
|
|
36064
|
+
throw new Error(`Compatibility handshake failed: unable to run "neurcode compat --json". ` +
|
|
36065
|
+
`Output: ${stripAnsi(compatResult.output).trim() || 'no output'}`);
|
|
36066
|
+
}
|
|
36067
|
+
const cliCompatPayload = extractLastJsonObject(compatResult.output);
|
|
36068
|
+
if (!cliCompatPayload) {
|
|
36069
|
+
throw new Error('Compatibility handshake failed: CLI compat output did not contain JSON.');
|
|
36070
|
+
}
|
|
36071
|
+
const cliCompatibility = (0, runtime_compat_1.parseCliCompatibilityPayload)(cliCompatPayload);
|
|
36072
|
+
let apiCompatibility = null;
|
|
36073
|
+
let apiVersion;
|
|
36074
|
+
if (input.apiUrl) {
|
|
36075
|
+
const apiHealthPayload = await resolveApiHealthPayload(input.apiUrl, 10000);
|
|
36076
|
+
apiCompatibility = (0, runtime_compat_1.parseApiHealthCompatibilityPayload)(apiHealthPayload);
|
|
36077
|
+
if (!apiCompatibility && input.requireApiCompatibility) {
|
|
36078
|
+
throw new Error('Compatibility handshake failed: API health payload does not include compatibility metadata.');
|
|
36079
|
+
}
|
|
36080
|
+
if (apiCompatibility?.componentVersion) {
|
|
36081
|
+
apiVersion = apiCompatibility.componentVersion;
|
|
36082
|
+
}
|
|
36083
|
+
else if (apiHealthPayload
|
|
36084
|
+
&& typeof apiHealthPayload === 'object'
|
|
36085
|
+
&& !Array.isArray(apiHealthPayload)
|
|
36086
|
+
&& typeof apiHealthPayload.version === 'string') {
|
|
36087
|
+
apiVersion = apiHealthPayload.version;
|
|
36088
|
+
}
|
|
36089
|
+
}
|
|
36090
|
+
const errors = (0, runtime_compat_1.validateActionHandshake)({
|
|
36091
|
+
actionVersion,
|
|
36092
|
+
cliCompatibility,
|
|
36093
|
+
apiCompatibility,
|
|
36094
|
+
requireApiCompatibility: input.requireApiCompatibility && Boolean(input.apiUrl),
|
|
36095
|
+
});
|
|
36096
|
+
if (errors.length > 0) {
|
|
36097
|
+
throw new Error(`Compatibility handshake failed:\n- ${errors.join('\n- ')}`);
|
|
36098
|
+
}
|
|
36099
|
+
return {
|
|
36100
|
+
actionVersion,
|
|
36101
|
+
cliVersion: cliCompatibility.componentVersion,
|
|
36102
|
+
apiVersion,
|
|
36103
|
+
};
|
|
36104
|
+
}
|
|
35735
36105
|
function parseVerifyResult(output) {
|
|
35736
36106
|
const parsed = extractLastJsonObject(output);
|
|
35737
36107
|
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed))
|
|
@@ -36140,6 +36510,24 @@ async function ensureCliInstalled(input) {
|
|
|
36140
36510
|
function withCliCommandTimeout(cli, args, timeoutMinutes) {
|
|
36141
36511
|
return withCommandTimeout(cli.cmd, [...cli.argsPrefix, ...args], timeoutMinutes);
|
|
36142
36512
|
}
|
|
36513
|
+
async function resolveVerifyCapabilities(cli, cwd) {
|
|
36514
|
+
const helpCommand = withCliCommandTimeout(cli, ['verify', '--help'], 2);
|
|
36515
|
+
const helpResult = await runCommand(helpCommand.cmd, helpCommand.args, { cwd });
|
|
36516
|
+
if (helpResult.exitCode !== 0) {
|
|
36517
|
+
core.warning('Unable to detect verify flag capabilities; defaulting to full verify flag set.');
|
|
36518
|
+
return {
|
|
36519
|
+
supportsCompiledPolicy: true,
|
|
36520
|
+
supportsChangeContract: true,
|
|
36521
|
+
supportsEnforceChangeContract: true,
|
|
36522
|
+
};
|
|
36523
|
+
}
|
|
36524
|
+
const helpText = stripAnsi(helpResult.output).toLowerCase();
|
|
36525
|
+
return {
|
|
36526
|
+
supportsCompiledPolicy: helpText.includes('--compiled-policy'),
|
|
36527
|
+
supportsChangeContract: helpText.includes('--change-contract'),
|
|
36528
|
+
supportsEnforceChangeContract: helpText.includes('--enforce-change-contract'),
|
|
36529
|
+
};
|
|
36530
|
+
}
|
|
36143
36531
|
async function resolveCliInvocation(cwd) {
|
|
36144
36532
|
const direct = await runCommand('neurcode', ['--version'], { cwd });
|
|
36145
36533
|
if (direct.exitCode === 0) {
|
|
@@ -36353,10 +36741,15 @@ async function run() {
|
|
|
36353
36741
|
const cliInstallSource = parseCliInstallSource(core.getInput('neurcode_cli_source'));
|
|
36354
36742
|
const cliWorkspacePath = core.getInput('neurcode_cli_workspace_path') || 'packages/cli';
|
|
36355
36743
|
const verifyTimeoutMinutes = parsePositiveInt(core.getInput('verify_timeout_minutes'), 8, 1, 120);
|
|
36744
|
+
const enforceCompatibilityHandshake = parseBoolean(core.getInput('enforce_compatibility_handshake'), true);
|
|
36745
|
+
const requireApiCompatibilityHandshake = parseBoolean(core.getInput('require_api_compatibility_handshake'), true);
|
|
36746
|
+
const compatibilityProbeTimeoutMinutes = parsePositiveInt(core.getInput('compatibility_probe_timeout_minutes'), 2, 1, 15);
|
|
36747
|
+
const configuredApiUrl = (process.env.NEURCODE_API_URL || '').trim();
|
|
36356
36748
|
const verifyPolicyOnly = parseBoolean(core.getInput('verify_policy_only'), false);
|
|
36749
|
+
const enterpriseMode = parseBoolean(core.getInput('enterprise_mode'), true);
|
|
36357
36750
|
const compiledPolicyPath = (core.getInput('compiled_policy_path') || 'neurcode.policy.compiled.json').trim();
|
|
36358
36751
|
const changeContractPath = (core.getInput('change_contract_path') || '.neurcode/change-contract.json').trim();
|
|
36359
|
-
const
|
|
36752
|
+
const enforceChangeContractOverride = parseBooleanOrUndefined(core.getInput('enforce_change_contract'));
|
|
36360
36753
|
const changedFilesOnly = parseBoolean(core.getInput('changed_files_only'), false);
|
|
36361
36754
|
const autoRemediate = parseBoolean(core.getInput('auto_remediate'), false);
|
|
36362
36755
|
const remediationGoalInput = core.getInput('remediation_goal') || '';
|
|
@@ -36370,7 +36763,15 @@ async function run() {
|
|
|
36370
36763
|
const shipNetworkRetryDelaySeconds = parsePositiveInt(core.getInput('ship_network_retry_delay_seconds'), 5, 0, 30);
|
|
36371
36764
|
const remediationCommit = parseBoolean(core.getInput('remediation_commit'), false);
|
|
36372
36765
|
const remediationPush = parseBoolean(core.getInput('remediation_push'), false);
|
|
36373
|
-
const
|
|
36766
|
+
const enforceStrictVerificationOverride = parseBooleanOrUndefined(core.getInput('enforce_strict_verification'));
|
|
36767
|
+
const enterpriseEnforcement = (0, verify_mode_1.resolveEnterpriseEnforcement)({
|
|
36768
|
+
enterpriseMode,
|
|
36769
|
+
verifyPolicyOnly,
|
|
36770
|
+
enforceChangeContract: enforceChangeContractOverride,
|
|
36771
|
+
enforceStrictVerification: enforceStrictVerificationOverride,
|
|
36772
|
+
});
|
|
36773
|
+
let enforceChangeContract = enterpriseEnforcement.enforceChangeContract;
|
|
36774
|
+
const enforceStrictVerification = enterpriseEnforcement.enforceStrictVerification;
|
|
36374
36775
|
const verifyAfterRemediation = parseBoolean(core.getInput('verify_after_remediation'), true);
|
|
36375
36776
|
const verifyAfterRemediationTimeoutMinutes = parsePositiveInt(core.getInput('verify_after_remediation_timeout_minutes'), verifyTimeoutMinutes, 1, 120);
|
|
36376
36777
|
const requireRemediationPushSuccess = parseBoolean(core.getInput('require_remediation_push_success'), false);
|
|
@@ -36398,6 +36799,52 @@ async function run() {
|
|
|
36398
36799
|
source: cliInstallSource,
|
|
36399
36800
|
workspacePath: cliWorkspacePath,
|
|
36400
36801
|
});
|
|
36802
|
+
if (enforceCompatibilityHandshake) {
|
|
36803
|
+
const handshake = await runCompatibilityHandshake({
|
|
36804
|
+
cli: cliInvocation,
|
|
36805
|
+
cwd,
|
|
36806
|
+
timeoutMinutes: compatibilityProbeTimeoutMinutes,
|
|
36807
|
+
apiUrl: configuredApiUrl || undefined,
|
|
36808
|
+
requireApiCompatibility: requireApiCompatibilityHandshake,
|
|
36809
|
+
});
|
|
36810
|
+
core.info(`Compatibility handshake passed (action=${handshake.actionVersion}, cli=${handshake.cliVersion}${handshake.apiVersion ? `, api=${handshake.apiVersion}` : ''}).`);
|
|
36811
|
+
core.setOutput('compatibility_handshake', 'passed');
|
|
36812
|
+
core.setOutput('compatibility_contract_version', contracts_1.RUNTIME_COMPATIBILITY_CONTRACT_VERSION);
|
|
36813
|
+
core.setOutput('compatibility_action_version', handshake.actionVersion);
|
|
36814
|
+
core.setOutput('compatibility_cli_version', handshake.cliVersion);
|
|
36815
|
+
if (handshake.apiVersion) {
|
|
36816
|
+
core.setOutput('compatibility_api_version', handshake.apiVersion);
|
|
36817
|
+
}
|
|
36818
|
+
}
|
|
36819
|
+
else {
|
|
36820
|
+
core.warning('Compatibility handshake is disabled via enforce_compatibility_handshake=false.');
|
|
36821
|
+
core.setOutput('compatibility_handshake', 'skipped');
|
|
36822
|
+
}
|
|
36823
|
+
const verifyCapabilities = await resolveVerifyCapabilities(cliInvocation, cwd);
|
|
36824
|
+
const effectiveCompiledPolicyPath = verifyCapabilities.supportsCompiledPolicy
|
|
36825
|
+
? (compiledPolicyPath || undefined)
|
|
36826
|
+
: undefined;
|
|
36827
|
+
const effectiveChangeContractPath = verifyCapabilities.supportsChangeContract
|
|
36828
|
+
? (changeContractPath || undefined)
|
|
36829
|
+
: undefined;
|
|
36830
|
+
if (!verifyCapabilities.supportsCompiledPolicy && compiledPolicyPath) {
|
|
36831
|
+
core.warning('CLI does not support --compiled-policy; compiled policy artifact input will be ignored.');
|
|
36832
|
+
}
|
|
36833
|
+
if (!verifyCapabilities.supportsChangeContract && changeContractPath) {
|
|
36834
|
+
core.warning('CLI does not support --change-contract; contract path input will be ignored.');
|
|
36835
|
+
}
|
|
36836
|
+
if (enforceChangeContract && !verifyCapabilities.supportsEnforceChangeContract) {
|
|
36837
|
+
core.warning('CLI does not support --enforce-change-contract; contract hard-fail mode will be disabled.');
|
|
36838
|
+
enforceChangeContract = false;
|
|
36839
|
+
}
|
|
36840
|
+
assertStrictDeterministicArtifacts({
|
|
36841
|
+
cwd,
|
|
36842
|
+
strictMode: enforceStrictVerification,
|
|
36843
|
+
compiledPolicyPath: effectiveCompiledPolicyPath,
|
|
36844
|
+
changeContractPath: effectiveChangeContractPath,
|
|
36845
|
+
supportsCompiledPolicy: verifyCapabilities.supportsCompiledPolicy,
|
|
36846
|
+
supportsChangeContract: verifyCapabilities.supportsChangeContract,
|
|
36847
|
+
});
|
|
36401
36848
|
const pr = github.context.payload.pull_request;
|
|
36402
36849
|
const defaultBaseRef = pr ? `origin/${pr.base.ref}` : 'HEAD~1';
|
|
36403
36850
|
const baseRef = baseRefInput.trim() || defaultBaseRef;
|
|
@@ -36405,6 +36852,9 @@ async function run() {
|
|
|
36405
36852
|
? `Running verify in PR context against ${baseRef}`
|
|
36406
36853
|
: `Running verify in push context against ${baseRef}`);
|
|
36407
36854
|
core.info(`Verification mode: ${verifyPolicyOnly ? 'policy-only' : 'plan-aware'}`);
|
|
36855
|
+
core.info(`Enterprise mode: ${enterpriseMode ? 'enabled' : 'disabled'}`);
|
|
36856
|
+
core.info(`Verify capabilities => compiled_policy=${verifyCapabilities.supportsCompiledPolicy}, change_contract=${verifyCapabilities.supportsChangeContract}, enforce_change_contract=${verifyCapabilities.supportsEnforceChangeContract}`);
|
|
36857
|
+
core.info(`Enterprise enforcement => enforce_change_contract=${enforceChangeContract}, enforce_strict_verification=${enforceStrictVerification}`);
|
|
36408
36858
|
let changedFiles = new Set();
|
|
36409
36859
|
if (changedFilesOnly) {
|
|
36410
36860
|
const changedFilesRun = await runCommand('git', ['diff', '--name-only', `${baseRef}...HEAD`], { cwd });
|
|
@@ -36417,6 +36867,7 @@ async function run() {
|
|
|
36417
36867
|
}
|
|
36418
36868
|
}
|
|
36419
36869
|
let effectiveVerifyPolicyOnly = verifyPolicyOnly;
|
|
36870
|
+
let effectiveEnforceChangeContract = enforceChangeContract;
|
|
36420
36871
|
const hasExplicitPlanId = Boolean(planId && planId.trim());
|
|
36421
36872
|
let policyOnlyFallbackUsed = false;
|
|
36422
36873
|
let fallbackFailureHint = null;
|
|
@@ -36426,9 +36877,10 @@ async function run() {
|
|
|
36426
36877
|
projectId: projectId || undefined,
|
|
36427
36878
|
policyOnly: effectiveVerifyPolicyOnly,
|
|
36428
36879
|
record,
|
|
36429
|
-
compiledPolicyPath:
|
|
36430
|
-
changeContractPath:
|
|
36431
|
-
enforceChangeContract,
|
|
36880
|
+
compiledPolicyPath: effectiveCompiledPolicyPath,
|
|
36881
|
+
changeContractPath: effectiveChangeContractPath,
|
|
36882
|
+
enforceChangeContract: effectiveEnforceChangeContract,
|
|
36883
|
+
strictArtifacts: enforceStrictVerification,
|
|
36432
36884
|
});
|
|
36433
36885
|
let verifyCommand = withCliCommandTimeout(cliInvocation, verifyArgs, verifyTimeoutMinutes);
|
|
36434
36886
|
let verifyRun = await runCommand(verifyCommand.cmd, verifyCommand.args, {
|
|
@@ -36451,15 +36903,22 @@ async function run() {
|
|
|
36451
36903
|
core.warning('Plan-aware verification failed due to missing plan context. Retrying with --policy-only fallback.');
|
|
36452
36904
|
policyOnlyFallbackUsed = true;
|
|
36453
36905
|
effectiveVerifyPolicyOnly = true;
|
|
36906
|
+
effectiveEnforceChangeContract =
|
|
36907
|
+
(typeof enforceChangeContractOverride === 'boolean' ? enforceChangeContractOverride : false)
|
|
36908
|
+
&& verifyCapabilities.supportsEnforceChangeContract;
|
|
36909
|
+
if (typeof enforceChangeContractOverride !== 'boolean' && enforceChangeContract) {
|
|
36910
|
+
core.info('Policy-only fallback detected; auto-disabling change-contract hard-fail for fallback run.');
|
|
36911
|
+
}
|
|
36454
36912
|
verifyArgs = (0, verify_mode_1.buildVerifyArgs)({
|
|
36455
36913
|
baseRef,
|
|
36456
36914
|
projectId: projectId || undefined,
|
|
36457
36915
|
planId: undefined,
|
|
36458
36916
|
policyOnly: true,
|
|
36459
36917
|
record,
|
|
36460
|
-
compiledPolicyPath:
|
|
36461
|
-
changeContractPath:
|
|
36462
|
-
enforceChangeContract,
|
|
36918
|
+
compiledPolicyPath: effectiveCompiledPolicyPath,
|
|
36919
|
+
changeContractPath: effectiveChangeContractPath,
|
|
36920
|
+
enforceChangeContract: effectiveEnforceChangeContract,
|
|
36921
|
+
strictArtifacts: enforceStrictVerification,
|
|
36463
36922
|
});
|
|
36464
36923
|
verifyCommand = withCliCommandTimeout(cliInvocation, verifyArgs, verifyTimeoutMinutes);
|
|
36465
36924
|
verifyRun = await runCommand(verifyCommand.cmd, verifyCommand.args, {
|
|
@@ -36715,6 +37174,9 @@ async function run() {
|
|
|
36715
37174
|
: 'plan_aware';
|
|
36716
37175
|
core.setOutput('verify_mode', verifyModeOutput);
|
|
36717
37176
|
core.setOutput('policy_only_fallback_used', policyOnlyFallbackUsed ? 'true' : 'false');
|
|
37177
|
+
core.setOutput('enterprise_mode_active', enterpriseMode ? 'true' : 'false');
|
|
37178
|
+
core.setOutput('enterprise_enforced_change_contract', effectiveEnforceChangeContract ? 'true' : 'false');
|
|
37179
|
+
core.setOutput('enterprise_enforced_strict_verification', enforceStrictVerification ? 'true' : 'false');
|
|
36718
37180
|
if (remediation) {
|
|
36719
37181
|
core.setOutput('remediation_status', remediation.status);
|
|
36720
37182
|
core.setOutput('merge_confidence', remediation.mergeConfidence);
|
|
@@ -36762,6 +37224,138 @@ async function run() {
|
|
|
36762
37224
|
run();
|
|
36763
37225
|
|
|
36764
37226
|
|
|
37227
|
+
/***/ }),
|
|
37228
|
+
|
|
37229
|
+
/***/ 5654:
|
|
37230
|
+
/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
|
|
37231
|
+
|
|
37232
|
+
"use strict";
|
|
37233
|
+
|
|
37234
|
+
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
37235
|
+
exports.parseCliCompatibilityPayload = parseCliCompatibilityPayload;
|
|
37236
|
+
exports.parseApiHealthCompatibilityPayload = parseApiHealthCompatibilityPayload;
|
|
37237
|
+
exports.validateActionHandshake = validateActionHandshake;
|
|
37238
|
+
const contracts_1 = __nccwpck_require__(7239);
|
|
37239
|
+
function asRecord(value, label) {
|
|
37240
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
37241
|
+
throw new Error(`${label}: expected object`);
|
|
37242
|
+
}
|
|
37243
|
+
return value;
|
|
37244
|
+
}
|
|
37245
|
+
function asString(record, key, label) {
|
|
37246
|
+
const value = record[key];
|
|
37247
|
+
if (typeof value !== 'string' || !value.trim()) {
|
|
37248
|
+
throw new Error(`${label}: expected ${key}:string`);
|
|
37249
|
+
}
|
|
37250
|
+
return value.trim();
|
|
37251
|
+
}
|
|
37252
|
+
function asRuntimeComponent(value, label) {
|
|
37253
|
+
if (value === 'cli' || value === 'action' || value === 'api') {
|
|
37254
|
+
return value;
|
|
37255
|
+
}
|
|
37256
|
+
throw new Error(`${label}: expected component "cli" | "action" | "api"`);
|
|
37257
|
+
}
|
|
37258
|
+
function parseMinimumPeerVersions(value, label) {
|
|
37259
|
+
if (value === undefined || value === null)
|
|
37260
|
+
return {};
|
|
37261
|
+
const record = asRecord(value, `${label}.minimumPeerVersions`);
|
|
37262
|
+
const next = {};
|
|
37263
|
+
for (const component of ['cli', 'action', 'api']) {
|
|
37264
|
+
const item = record[component];
|
|
37265
|
+
if (item === undefined)
|
|
37266
|
+
continue;
|
|
37267
|
+
if (typeof item !== 'string' || !item.trim()) {
|
|
37268
|
+
throw new Error(`${label}.minimumPeerVersions: expected ${component}:string`);
|
|
37269
|
+
}
|
|
37270
|
+
next[component] = item.trim();
|
|
37271
|
+
}
|
|
37272
|
+
return next;
|
|
37273
|
+
}
|
|
37274
|
+
function parseDescriptor(value, label) {
|
|
37275
|
+
const record = asRecord(value, label);
|
|
37276
|
+
return {
|
|
37277
|
+
contractId: asString(record, 'contractId', label),
|
|
37278
|
+
runtimeContractVersion: asString(record, 'runtimeContractVersion', label),
|
|
37279
|
+
cliJsonContractVersion: asString(record, 'cliJsonContractVersion', label),
|
|
37280
|
+
component: asRuntimeComponent(asString(record, 'component', label), label),
|
|
37281
|
+
componentVersion: asString(record, 'componentVersion', label),
|
|
37282
|
+
minimumPeerVersions: parseMinimumPeerVersions(record.minimumPeerVersions, label),
|
|
37283
|
+
};
|
|
37284
|
+
}
|
|
37285
|
+
function parseCliCompatibilityPayload(value) {
|
|
37286
|
+
const parsed = (0, contracts_1.parseCliCompatJsonPayload)(value, 'action-cli-compat');
|
|
37287
|
+
if (parsed.success !== true) {
|
|
37288
|
+
throw new Error('action-cli-compat: success=false');
|
|
37289
|
+
}
|
|
37290
|
+
const descriptor = parseDescriptor(parsed.compatibility, 'action-cli-compat.compatibility');
|
|
37291
|
+
return {
|
|
37292
|
+
source: 'cli',
|
|
37293
|
+
...descriptor,
|
|
37294
|
+
};
|
|
37295
|
+
}
|
|
37296
|
+
function parseApiHealthCompatibilityPayload(value) {
|
|
37297
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
37298
|
+
return null;
|
|
37299
|
+
}
|
|
37300
|
+
const record = value;
|
|
37301
|
+
if (!record.compatibility) {
|
|
37302
|
+
return null;
|
|
37303
|
+
}
|
|
37304
|
+
const descriptor = parseDescriptor(record.compatibility, 'action-api-compat.compatibility');
|
|
37305
|
+
return {
|
|
37306
|
+
source: 'api',
|
|
37307
|
+
...descriptor,
|
|
37308
|
+
};
|
|
37309
|
+
}
|
|
37310
|
+
function validateVersionMinimum(label, actual, required, errors) {
|
|
37311
|
+
if (!required)
|
|
37312
|
+
return;
|
|
37313
|
+
const isCompatible = (0, contracts_1.isSemverAtLeast)(actual, required);
|
|
37314
|
+
if (isCompatible === null) {
|
|
37315
|
+
errors.push(`${label}: unable to compare versions (actual=${actual}, required=${required}).`);
|
|
37316
|
+
return;
|
|
37317
|
+
}
|
|
37318
|
+
if (!isCompatible) {
|
|
37319
|
+
errors.push(`${label}: actual=${actual} is below required=${required}.`);
|
|
37320
|
+
}
|
|
37321
|
+
}
|
|
37322
|
+
function validateContractEnvelope(descriptor, expectedComponent, errors) {
|
|
37323
|
+
if (descriptor.component !== expectedComponent) {
|
|
37324
|
+
errors.push(`${descriptor.source} compatibility payload expected component=${expectedComponent} but received ${descriptor.component}.`);
|
|
37325
|
+
}
|
|
37326
|
+
if (descriptor.contractId !== contracts_1.RUNTIME_COMPATIBILITY_CONTRACT_ID) {
|
|
37327
|
+
errors.push(`${descriptor.source} compatibility payload has unexpected contractId=${descriptor.contractId} (expected ${contracts_1.RUNTIME_COMPATIBILITY_CONTRACT_ID}).`);
|
|
37328
|
+
}
|
|
37329
|
+
if (descriptor.runtimeContractVersion !== contracts_1.RUNTIME_COMPATIBILITY_CONTRACT_VERSION) {
|
|
37330
|
+
errors.push(`${descriptor.source} compatibility payload has runtimeContractVersion=${descriptor.runtimeContractVersion} (expected ${contracts_1.RUNTIME_COMPATIBILITY_CONTRACT_VERSION}).`);
|
|
37331
|
+
}
|
|
37332
|
+
if (descriptor.cliJsonContractVersion !== contracts_1.CLI_JSON_CONTRACT_VERSION) {
|
|
37333
|
+
errors.push(`${descriptor.source} compatibility payload has cliJsonContractVersion=${descriptor.cliJsonContractVersion} (expected ${contracts_1.CLI_JSON_CONTRACT_VERSION}).`);
|
|
37334
|
+
}
|
|
37335
|
+
}
|
|
37336
|
+
function validateActionHandshake(input) {
|
|
37337
|
+
const errors = [];
|
|
37338
|
+
const { actionVersion, cliCompatibility } = input;
|
|
37339
|
+
const apiCompatibility = input.apiCompatibility || null;
|
|
37340
|
+
const requireApiCompatibility = input.requireApiCompatibility === true;
|
|
37341
|
+
validateContractEnvelope(cliCompatibility, 'cli', errors);
|
|
37342
|
+
validateVersionMinimum('CLI version required by action', cliCompatibility.componentVersion, (0, contracts_1.getMinimumCompatiblePeerVersion)('action', 'cli'), errors);
|
|
37343
|
+
validateVersionMinimum('Action version required by CLI payload', actionVersion, cliCompatibility.minimumPeerVersions.action, errors);
|
|
37344
|
+
if (!apiCompatibility) {
|
|
37345
|
+
if (requireApiCompatibility) {
|
|
37346
|
+
errors.push('API compatibility payload missing while API compatibility handshake is required.');
|
|
37347
|
+
}
|
|
37348
|
+
return errors;
|
|
37349
|
+
}
|
|
37350
|
+
validateContractEnvelope(apiCompatibility, 'api', errors);
|
|
37351
|
+
validateVersionMinimum('API version required by action', apiCompatibility.componentVersion, (0, contracts_1.getMinimumCompatiblePeerVersion)('action', 'api'), errors);
|
|
37352
|
+
validateVersionMinimum('Action version required by API payload', actionVersion, apiCompatibility.minimumPeerVersions.action, errors);
|
|
37353
|
+
validateVersionMinimum('CLI version required by API payload', cliCompatibility.componentVersion, apiCompatibility.minimumPeerVersions.cli, errors);
|
|
37354
|
+
validateVersionMinimum('API version required by CLI payload', apiCompatibility.componentVersion, cliCompatibility.minimumPeerVersions.api, errors);
|
|
37355
|
+
return errors;
|
|
37356
|
+
}
|
|
37357
|
+
|
|
37358
|
+
|
|
36765
37359
|
/***/ }),
|
|
36766
37360
|
|
|
36767
37361
|
/***/ 4288:
|
|
@@ -36772,6 +37366,7 @@ run();
|
|
|
36772
37366
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
36773
37367
|
exports.isMissingPlanVerificationFailure = isMissingPlanVerificationFailure;
|
|
36774
37368
|
exports.buildVerifyArgs = buildVerifyArgs;
|
|
37369
|
+
exports.resolveEnterpriseEnforcement = resolveEnterpriseEnforcement;
|
|
36775
37370
|
exports.getVerifyFallbackDecision = getVerifyFallbackDecision;
|
|
36776
37371
|
const ANSI_PATTERN = /\u001b\[[0-9;]*m/g;
|
|
36777
37372
|
const MISSING_PLAN_VERIFY_PATTERNS = [
|
|
@@ -36807,10 +37402,24 @@ function buildVerifyArgs(input) {
|
|
|
36807
37402
|
args.push('--change-contract', input.changeContractPath);
|
|
36808
37403
|
if (input.enforceChangeContract)
|
|
36809
37404
|
args.push('--enforce-change-contract');
|
|
37405
|
+
if (input.strictArtifacts)
|
|
37406
|
+
args.push('--strict-artifacts');
|
|
36810
37407
|
if (input.record)
|
|
36811
37408
|
args.push('--record');
|
|
36812
37409
|
return args;
|
|
36813
37410
|
}
|
|
37411
|
+
function resolveEnterpriseEnforcement(input) {
|
|
37412
|
+
const enforceChangeContract = typeof input.enforceChangeContract === 'boolean'
|
|
37413
|
+
? input.enforceChangeContract
|
|
37414
|
+
: (input.enterpriseMode && !input.verifyPolicyOnly);
|
|
37415
|
+
const enforceStrictVerification = typeof input.enforceStrictVerification === 'boolean'
|
|
37416
|
+
? input.enforceStrictVerification
|
|
37417
|
+
: input.enterpriseMode;
|
|
37418
|
+
return {
|
|
37419
|
+
enforceChangeContract,
|
|
37420
|
+
enforceStrictVerification,
|
|
37421
|
+
};
|
|
37422
|
+
}
|
|
36814
37423
|
function getVerifyFallbackDecision(input) {
|
|
36815
37424
|
if (input.verifyExitCode === 0) {
|
|
36816
37425
|
return { shouldRetryPolicyOnly: false, reason: 'verify_succeeded' };
|