@skydiveai/git-cache 0.1.0-beta.1635 → 0.1.0-beta.2411
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/cli.mjs +1 -1
- package/dist/index.d.mts +1 -0
- package/dist/index.mjs +1 -1
- package/dist/{server-DfaJ_V9K.mjs → server-DDcKo4yG.mjs} +31 -20
- package/package.json +1 -10
package/dist/cli.mjs
CHANGED
package/dist/index.d.mts
CHANGED
package/dist/index.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as isProtocolV2Request, c as parseAdvertisement, d as shouldBackfillAfterPassthrough, f as startServer, i as explainRejection, l as parseUpstream, n as classifyUploadRequest, o as metricsSnapshot, r as copyRequestHeaders, s as mirrorHasObjects, t as SidebandPackExtractor, u as recordColdBuildOutcome } from "./server-
|
|
1
|
+
import { a as isProtocolV2Request, c as parseAdvertisement, d as shouldBackfillAfterPassthrough, f as startServer, i as explainRejection, l as parseUpstream, n as classifyUploadRequest, o as metricsSnapshot, r as copyRequestHeaders, s as mirrorHasObjects, t as SidebandPackExtractor, u as recordColdBuildOutcome } from "./server-DDcKo4yG.mjs";
|
|
2
2
|
export { SidebandPackExtractor, classifyUploadRequest, copyRequestHeaders, explainRejection, isProtocolV2Request, metricsSnapshot, mirrorHasObjects, parseAdvertisement, parseUpstream, recordColdBuildOutcome, shouldBackfillAfterPassthrough, startServer };
|
|
@@ -298,12 +298,12 @@ function evictAuthCache() {
|
|
|
298
298
|
}
|
|
299
299
|
function validateUpstream(credHeader, upstreamUrl) {
|
|
300
300
|
return new Promise((resolve) => {
|
|
301
|
-
const
|
|
301
|
+
const target = new URL(`${upstreamUrl}/info/refs?service=git-upload-pack`);
|
|
302
|
+
const headers = { "user-agent": "git/git-cache-authz" };
|
|
303
|
+
if (credHeader !== null) headers["authorization"] = credHeader;
|
|
304
|
+
const request = requestUpstream(target, {
|
|
302
305
|
method: "GET",
|
|
303
|
-
headers
|
|
304
|
-
authorization: credHeader,
|
|
305
|
-
"user-agent": "git/git-cache-authz"
|
|
306
|
-
}
|
|
306
|
+
headers
|
|
307
307
|
}, (res) => {
|
|
308
308
|
res.resume();
|
|
309
309
|
const status = res.statusCode ?? 502;
|
|
@@ -341,7 +341,7 @@ function validateUpstream(credHeader, upstreamUrl) {
|
|
|
341
341
|
});
|
|
342
342
|
}
|
|
343
343
|
async function authorizeCheckThrough(credHeader, repo, upstreamUrl) {
|
|
344
|
-
const key = authMemoKey(credHeader, repo);
|
|
344
|
+
const key = authMemoKey(credHeader ?? "", repo);
|
|
345
345
|
const cached = authCache.get(key);
|
|
346
346
|
if (cached) {
|
|
347
347
|
const ttl = cached.allowed ? AUTH_ALLOW_TTL_MS : AUTH_DENY_TTL_MS;
|
|
@@ -437,14 +437,12 @@ function parseUpstream(rawPathname, rawSearch = "") {
|
|
|
437
437
|
const hadDotGit = Boolean(match[3]);
|
|
438
438
|
const operation = match[4];
|
|
439
439
|
let host = authority;
|
|
440
|
-
let port = 443;
|
|
441
440
|
const colon = authority.lastIndexOf(":");
|
|
442
441
|
if (colon !== -1) {
|
|
443
442
|
host = authority.slice(0, colon);
|
|
444
443
|
const p = authority.slice(colon + 1);
|
|
445
444
|
if (!/^\d{1,5}$/.test(p)) return null;
|
|
446
|
-
|
|
447
|
-
if (port !== 443) return null;
|
|
445
|
+
if (Number(p) !== 443) return null;
|
|
448
446
|
}
|
|
449
447
|
host = host.toLowerCase();
|
|
450
448
|
if (isIpLiteral(host)) return null;
|
|
@@ -1681,6 +1679,16 @@ async function proxyInfoRefs(req, res, repo, upstreamUrl, host, credHeader) {
|
|
|
1681
1679
|
}, cred);
|
|
1682
1680
|
});
|
|
1683
1681
|
}
|
|
1682
|
+
function requestErrorContext(req) {
|
|
1683
|
+
const rawTarget = req.url ?? "";
|
|
1684
|
+
const target = (rawTarget.split("?", 1)[0] ?? "").replace(/^\/[^/?#@]+@/, "/[redacted]@").replace(/^(https?:\/\/)[^/?#@]+@/, "$1[redacted]@");
|
|
1685
|
+
return {
|
|
1686
|
+
method: req.method ?? null,
|
|
1687
|
+
target,
|
|
1688
|
+
targetLength: rawTarget.length,
|
|
1689
|
+
peer: req.socket?.remoteAddress ?? null
|
|
1690
|
+
};
|
|
1691
|
+
}
|
|
1684
1692
|
async function handle(req, res) {
|
|
1685
1693
|
const parsed = new URL(req.url, "http://git-cache.local");
|
|
1686
1694
|
if (parsed.pathname === "/healthz") {
|
|
@@ -1737,16 +1745,15 @@ async function handle(req, res) {
|
|
|
1737
1745
|
if (config.authMode === "check-through") {
|
|
1738
1746
|
const header = req.headers["authorization"];
|
|
1739
1747
|
const raw = Array.isArray(header) ? header[0] : header;
|
|
1740
|
-
|
|
1741
|
-
metrics.auth_denials++;
|
|
1742
|
-
res.writeHead(401, {
|
|
1743
|
-
"Content-Type": "text/plain",
|
|
1744
|
-
"WWW-Authenticate": "Basic realm=\"git-cache\""
|
|
1745
|
-
});
|
|
1746
|
-
return res.end("authentication required\n");
|
|
1747
|
-
}
|
|
1748
|
-
const verdict = await authorizeCheckThrough(raw, up.repo, up.upstreamUrl);
|
|
1748
|
+
const verdict = await authorizeCheckThrough(raw ?? null, up.repo, up.upstreamUrl);
|
|
1749
1749
|
if (!verdict.allowed) {
|
|
1750
|
+
if (!raw && (verdict.status === 401 || verdict.status === 403)) {
|
|
1751
|
+
res.writeHead(401, {
|
|
1752
|
+
"Content-Type": "text/plain",
|
|
1753
|
+
"WWW-Authenticate": "Basic realm=\"git-cache\""
|
|
1754
|
+
});
|
|
1755
|
+
return res.end("authentication required\n");
|
|
1756
|
+
}
|
|
1750
1757
|
log("info", "auth_denied", {
|
|
1751
1758
|
repo: up.repo,
|
|
1752
1759
|
status: verdict.status
|
|
@@ -1754,7 +1761,7 @@ async function handle(req, res) {
|
|
|
1754
1761
|
res.writeHead(verdict.status, { "Content-Type": "text/plain" });
|
|
1755
1762
|
return res.end("not authorized for this repository\n");
|
|
1756
1763
|
}
|
|
1757
|
-
clientCred = raw;
|
|
1764
|
+
clientCred = raw ?? null;
|
|
1758
1765
|
}
|
|
1759
1766
|
const host = up.repo.split("/")[0] ?? "";
|
|
1760
1767
|
let uploadBody = null;
|
|
@@ -1852,7 +1859,11 @@ async function startServer(options = {}) {
|
|
|
1852
1859
|
await cleanupQuarantine();
|
|
1853
1860
|
const server = http.createServer((req, res) => {
|
|
1854
1861
|
handle(req, res).catch((error) => {
|
|
1855
|
-
log("error", "unhandled", {
|
|
1862
|
+
log("error", "unhandled", {
|
|
1863
|
+
error: String(error),
|
|
1864
|
+
stack: error instanceof Error ? error.stack : null,
|
|
1865
|
+
...requestErrorContext(req)
|
|
1866
|
+
});
|
|
1856
1867
|
if (!res.headersSent) res.writeHead(500);
|
|
1857
1868
|
res.end();
|
|
1858
1869
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@skydiveai/git-cache",
|
|
3
|
-
"version": "0.1.0-beta.
|
|
3
|
+
"version": "0.1.0-beta.2411",
|
|
4
4
|
"description": "Sandbox-local Git smart-HTTP clone/fetch cache: a loopback daemon that transparently mirrors HTTPS git reads so repeated clone/fetch/ls-remote skip the origin round-trip. Runs inside an agent sandbox; pushes stay direct.",
|
|
5
5
|
"homepage": "https://skydive.com",
|
|
6
6
|
"license": "MIT",
|
|
@@ -20,15 +20,6 @@
|
|
|
20
20
|
}
|
|
21
21
|
},
|
|
22
22
|
"publishConfig": {
|
|
23
|
-
"bin": {
|
|
24
|
-
"git-cache-daemon": "./dist/cli.mjs"
|
|
25
|
-
},
|
|
26
|
-
"exports": {
|
|
27
|
-
".": {
|
|
28
|
-
"types": "./dist/index.d.mts",
|
|
29
|
-
"default": "./dist/index.mjs"
|
|
30
|
-
}
|
|
31
|
-
},
|
|
32
23
|
"access": "public",
|
|
33
24
|
"registry": "https://registry.npmjs.org"
|
|
34
25
|
},
|