zephyr-agent
Version:
Zephyr plugin agent
179 lines (178 loc) • 8.67 kB
JavaScript
;
var __webpack_require__ = {};
(()=>{
__webpack_require__.d = (exports1, getters, values)=>{
var define = (defs, kind)=>{
for(var key in defs)if (__webpack_require__.o(defs, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
enumerable: true,
[kind]: defs[key]
});
};
define(getters, "get");
define(values, "value");
};
})();
(()=>{
__webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop);
})();
(()=>{
__webpack_require__.r = (exports1)=>{
if ("u" > typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
value: 'Module'
});
Object.defineProperty(exports1, '__esModule', {
value: true
});
};
})();
var __webpack_exports__ = {};
__webpack_require__.r(__webpack_exports__);
__webpack_require__.d(__webpack_exports__, {
publishAttribution: ()=>publishAttribution,
resolveRemoteContent: ()=>resolveRemoteContent
});
const external_node_crypto_namespaceObject = require("node:crypto");
const external_node_path_namespaceObject = require("node:path");
const external_node_fs_namespaceObject = require("node:fs");
const external_zephyr_edge_contract_namespaceObject = require("zephyr-edge-contract");
const token_js_namespaceObject = require("../node-persist/token.js");
const http_request_js_namespaceObject = require("../http/http-request.js");
const external_config_js_namespaceObject = require("./config.js");
const external_source_js_namespaceObject = require("./source.js");
const external_compare_js_namespaceObject = require("./compare.js");
function validPolicy(policy) {
return Boolean(policy && 1 === policy.schemaVersion && 'string' == typeof policy.repositoryId && /^[a-zA-Z0-9._-]{1,128}$/.test(policy.repositoryId) && 'string' == typeof policy.revision && policy.revision.length > 0 && policy.revision.length <= 128 && [
'free',
'paid',
'byoc'
].includes(policy.tier) && [
'local',
'remote'
].includes(policy.storage) && 'boolean' == typeof policy.content?.patch && 'boolean' == typeof policy.content?.lines);
}
function resolveRemoteContent(config, policy) {
if (!validPolicy(policy) || 'remote' !== policy.storage) throw new Error('Remote attribution needs an enabled repository policy from the authenticated service');
if (config.repositoryId && config.repositoryId !== policy.repositoryId) throw new Error('Attribution repository does not match the authenticated policy');
if ('free' === policy.tier) {
if (config.content?.patch === false || config.content?.lines === false || !policy.content.patch || !policy.content.lines) throw new Error('Free remote attribution requires patches and changed lines; choose local storage to keep them local');
return {
patch: true,
lines: true
};
}
const content = {
patch: config.content?.patch ?? false,
lines: config.content?.lines ?? false
};
if (content.patch && !policy.content.patch || content.lines && !policy.content.lines) throw new Error('Repository content settings exceed the authenticated attribution policy');
return content;
}
async function publishAttribution({ directory, summary, applicationUid, buildId, snapshotId, appConfig }) {
let repository;
try {
repository = (0, external_source_js_namespaceObject.attributionRepository)(directory);
} catch {
return;
}
const { root, gitDir } = repository;
let config;
try {
config = (0, external_config_js_namespaceObject.readAttributionConfig)(root, gitDir);
} catch {
return;
}
if (!config?.enabled || (config.storage ?? 'local') === 'local') return;
if (!summary || 'captured' !== summary.status || !summary.sourceId) throw new Error('Remote attribution cannot publish without a complete local source receipt');
if ('remote' !== summary.storage) throw new Error('Attribution storage changed during publication; capture again');
if (appConfig.application_uid !== applicationUid || !applicationUid || !buildId || !snapshotId) throw new Error('Attribution publication requires matching application and build identities');
const policy = appConfig.ATTRIBUTION_POLICY;
const content = resolveRemoteContent(config, policy);
const record = (0, external_source_js_namespaceObject.loadSourceRecord)(root, summary.sourceId);
if (record.fingerprint !== summary.sourceFingerprint) throw new Error('Attribution source receipt does not match its fingerprint');
const payload = {
schemaVersion: 1,
applicationUid,
repositoryId: policy.repositoryId,
buildId,
snapshotId,
policyRevision: policy.revision,
content,
attribution: summary
};
if (content.patch || content.lines) {
const difference = (0, external_compare_js_namespaceObject.compareSourceContents)((0, external_source_js_namespaceObject.sourceCommitBaseline)(root, record), record, root);
payload.comparison = {
base: 'git-head',
baseCommit: record.baseCommit,
changes: difference.changes.map(({ patch, lines, ...metadata })=>({
...metadata,
...content.patch ? {
patch
} : {},
...content.lines ? {
lines
} : {}
}))
};
}
const body = JSON.stringify(payload);
if (Buffer.byteLength(body) > 20971520) throw new Error('Remote attribution exceeds 20 MiB; reduce the repository capture scope');
const url = new URL(external_zephyr_edge_contract_namespaceObject.ze_api_gateway.attribution, (0, external_zephyr_edge_contract_namespaceObject.ZE_API_ENDPOINT)());
if ('https:' !== url.protocol && !('http:' === url.protocol && [
'localhost',
'127.0.0.1',
'[::1]'
].includes(url.hostname))) throw new Error('Remote attribution requires HTTPS');
if (url.username || url.password) throw new Error('Attribution endpoints must not contain credentials');
const token = await (0, token_js_namespaceObject.getToken)();
if (!token) throw new Error('Remote attribution requires Zephyr authentication');
const idempotencyKey = (0, external_node_crypto_namespaceObject.createHash)('sha256').update(JSON.stringify([
applicationUid,
policy.repositoryId,
buildId
])).digest('hex');
const [ok, , response] = await (0, http_request_js_namespaceObject.makeRequest)(url, {
method: 'POST',
redirect: 'error',
sensitiveResponse: true,
headers: {
'Content-Type': 'application/json',
Accept: 'application/json',
Authorization: `Bearer ${token}`,
'Idempotency-Key': idempotencyKey
},
credentialToken: token
}, body);
if (!ok || response?.status !== 'ok' || response.applicationUid !== applicationUid || response.repositoryId !== policy.repositoryId || response.buildId !== buildId || response.snapshotId !== snapshotId || response.sourceFingerprint !== record.fingerprint || 'string' != typeof response.recordId || !/^[a-zA-Z0-9._-]{1,128}$/.test(response.recordId)) throw new Error('Remote attribution was not acknowledged for this repository/build; private evidence remains local');
const remote = {
recordId: response.recordId,
repositoryId: policy.repositoryId,
policyRevision: policy.revision
};
(0, external_node_fs_namespaceObject.writeFileSync)((0, external_node_path_namespaceObject.join)(gitDir, 'zephyr-attribution', `remote-${idempotencyKey}.json`), JSON.stringify({
applicationUid,
buildId,
snapshotId,
sourceId: record.id,
sourceFingerprint: record.fingerprint,
remote
}), {
mode: 384
});
const { files: _files, sessions: _sessions, workspaceHuman: _human, ...reference } = summary;
return {
...reference,
storage: 'remote',
remote
};
}
exports.publishAttribution = __webpack_exports__.publishAttribution;
exports.resolveRemoteContent = __webpack_exports__.resolveRemoteContent;
for(var __rspack_i in __webpack_exports__)if (-1 === [
"publishAttribution",
"resolveRemoteContent"
].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
Object.defineProperty(exports, '__esModule', {
value: true
});
//# sourceMappingURL=remote.js.map