UNPKG

zephyr-agent

Version:
179 lines (178 loc) • 8.67 kB
"use strict"; 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