map: tickets 06+07 resolved; 05 partial (live spawn pending gitea token)
This commit is contained in:
+51
-50
@@ -13,54 +13,55 @@ const HTTP_UNAUTHORIZED = 401;
|
||||
const HTTP_NOT_FOUND = 404;
|
||||
|
||||
export function startFakeGitLab() {
|
||||
const seen = { userAuths: [], repoAuths: [] };
|
||||
const server = http.createServer((req, res) => {
|
||||
const auth = String(req.headers["authorization"] ?? "");
|
||||
const send = (code, obj) => {
|
||||
res.writeHead(code, { "Content-Type": "application/json" });
|
||||
res.end(JSON.stringify(obj));
|
||||
};
|
||||
if (req.url.startsWith("/api/v1/user/repos")) {
|
||||
seen.repoAuths.push(auth);
|
||||
if (auth !== `token ${GOOD_PAT}`) return send(HTTP_UNAUTHORIZED, { message: "401 Unauthorized" });
|
||||
const base = `http://127.0.0.1:${server.address().port}`;
|
||||
return send(HTTP_OK, [
|
||||
{
|
||||
full_name: "lvmh/beta",
|
||||
name: "beta",
|
||||
owner: { login: "lvmh" },
|
||||
updated_at: "2025-07-01T10:00:00Z",
|
||||
html_url: `${base}/lvmh/beta`,
|
||||
default_branch: "main",
|
||||
},
|
||||
{
|
||||
full_name: "lvmh/alpha",
|
||||
name: "alpha",
|
||||
owner: { login: "lvmh" },
|
||||
updated_at: "2025-08-01T10:00:00Z",
|
||||
html_url: `${base}/lvmh/alpha`,
|
||||
default_branch: "trunk",
|
||||
},
|
||||
]);
|
||||
}
|
||||
if (req.url.startsWith("/api/v1/user")) {
|
||||
seen.userAuths.push(auth);
|
||||
return auth === `token ${GOOD_PAT}`
|
||||
? send(HTTP_OK, { id: 1, login: "e2e-user", name: "E2E User" })
|
||||
: send(HTTP_UNAUTHORIZED, { message: "401 Unauthorized" });
|
||||
}
|
||||
return send(HTTP_NOT_FOUND, { message: "404 Not Found" });
|
||||
});
|
||||
return new Promise((resolve) => {
|
||||
server.listen(0, "127.0.0.1", () => {
|
||||
resolve({
|
||||
url: `http://127.0.0.1:${server.address().port}`,
|
||||
pat: GOOD_PAT,
|
||||
seen,
|
||||
close() {
|
||||
server.close();
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
const seen = { userAuths: [], repoAuths: [] };
|
||||
const server = http.createServer((req, res) => {
|
||||
const auth = String(req.headers["authorization"] ?? "");
|
||||
const send = (code, obj) => {
|
||||
res.writeHead(code, { "Content-Type": "application/json" });
|
||||
res.end(JSON.stringify(obj));
|
||||
};
|
||||
if (req.url.startsWith("/api/v1/user/repos")) {
|
||||
seen.repoAuths.push(auth);
|
||||
if (auth !== `token ${GOOD_PAT}`)
|
||||
return send(HTTP_UNAUTHORIZED, { message: "401 Unauthorized" });
|
||||
const base = `http://127.0.0.1:${server.address().port}`;
|
||||
return send(HTTP_OK, [
|
||||
{
|
||||
full_name: "lvmh/beta",
|
||||
name: "beta",
|
||||
owner: { login: "lvmh" },
|
||||
updated_at: "2025-07-01T10:00:00Z",
|
||||
html_url: `${base}/lvmh/beta`,
|
||||
default_branch: "main",
|
||||
},
|
||||
{
|
||||
full_name: "lvmh/alpha",
|
||||
name: "alpha",
|
||||
owner: { login: "lvmh" },
|
||||
updated_at: "2025-08-01T10:00:00Z",
|
||||
html_url: `${base}/lvmh/alpha`,
|
||||
default_branch: "trunk",
|
||||
},
|
||||
]);
|
||||
}
|
||||
if (req.url.startsWith("/api/v1/user")) {
|
||||
seen.userAuths.push(auth);
|
||||
return auth === `token ${GOOD_PAT}`
|
||||
? send(HTTP_OK, { id: 1, login: "e2e-user", name: "E2E User" })
|
||||
: send(HTTP_UNAUTHORIZED, { message: "401 Unauthorized" });
|
||||
}
|
||||
return send(HTTP_NOT_FOUND, { message: "404 Not Found" });
|
||||
});
|
||||
return new Promise((resolve) => {
|
||||
server.listen(0, "127.0.0.1", () => {
|
||||
resolve({
|
||||
url: `http://127.0.0.1:${server.address().port}`,
|
||||
pat: GOOD_PAT,
|
||||
seen,
|
||||
close() {
|
||||
server.close();
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
+71
-47
@@ -5,56 +5,80 @@
|
||||
import { rest } from "../lib.mjs";
|
||||
|
||||
export async function run(ctx) {
|
||||
const { r, base, token, gitlab } = ctx;
|
||||
const { r, base, token, gitlab } = ctx;
|
||||
|
||||
const connect = await rest(base, token, "/api/gitlab/connect", {
|
||||
method: "POST",
|
||||
body: { token: gitlab.pat },
|
||||
});
|
||||
r.check(
|
||||
"POST /api/gitlab/connect → 200 {username}",
|
||||
connect.status === 200 && connect.json?.username === "e2e-user",
|
||||
`got ${connect.status} ${connect.text}`,
|
||||
);
|
||||
r.check(
|
||||
"daemon validated token against fake /api/v1/user",
|
||||
gitlab.seen.userAuths.length === 1 && gitlab.seen.userAuths[0] === `token ${gitlab.pat}`,
|
||||
JSON.stringify(gitlab.seen.userAuths),
|
||||
);
|
||||
const connect = await rest(base, token, "/api/gitlab/connect", {
|
||||
method: "POST",
|
||||
body: { token: gitlab.pat },
|
||||
});
|
||||
r.check(
|
||||
"POST /api/gitlab/connect → 200 {username}",
|
||||
connect.status === 200 && connect.json?.username === "e2e-user",
|
||||
`got ${connect.status} ${connect.text}`,
|
||||
);
|
||||
r.check(
|
||||
"daemon validated token against fake /api/v1/user",
|
||||
gitlab.seen.userAuths.length === 1 &&
|
||||
gitlab.seen.userAuths[0] === `token ${gitlab.pat}`,
|
||||
JSON.stringify(gitlab.seen.userAuths),
|
||||
);
|
||||
|
||||
const status = await rest(base, token, "/api/gitlab/status");
|
||||
r.check(
|
||||
"status shows connected with username + baseUrl",
|
||||
status.json?.connected === true && status.json?.username === "e2e-user" && status.json?.baseUrl === gitlab.url,
|
||||
JSON.stringify(status.json),
|
||||
);
|
||||
const status = await rest(base, token, "/api/gitlab/status");
|
||||
r.check(
|
||||
"status shows connected with username + baseUrl",
|
||||
status.json?.connected === true &&
|
||||
status.json?.username === "e2e-user" &&
|
||||
status.json?.baseUrl === gitlab.url,
|
||||
JSON.stringify(status.json),
|
||||
);
|
||||
|
||||
const repos = await rest(base, token, "/api/gitlab/repos");
|
||||
r.check(
|
||||
"repos mapped to protocol shape",
|
||||
Array.isArray(repos.json) && repos.json.length === 2 &&
|
||||
repos.json.every((p) => typeof p.path === "string" && typeof p.name === "string" && typeof p.namespace === "string" && typeof p.lastActivityAt === "string" && typeof p.webUrl === "string" && typeof p.defaultBranch === "string"),
|
||||
JSON.stringify(repos.json ?? null),
|
||||
);
|
||||
r.check(
|
||||
"repos sorted by lastActivityAt desc (daemon-side sort)",
|
||||
repos.json?.[0]?.path === "lvmh/alpha" && repos.json?.[1]?.path === "lvmh/beta" &&
|
||||
repos.json?.[0]?.defaultBranch === "trunk",
|
||||
JSON.stringify((repos.json ?? []).map((p) => p.path)),
|
||||
);
|
||||
const repos = await rest(base, token, "/api/gitlab/repos");
|
||||
r.check(
|
||||
"repos mapped to protocol shape",
|
||||
Array.isArray(repos.json) &&
|
||||
repos.json.length === 2 &&
|
||||
repos.json.every(
|
||||
(p) =>
|
||||
typeof p.path === "string" &&
|
||||
typeof p.name === "string" &&
|
||||
typeof p.namespace === "string" &&
|
||||
typeof p.lastActivityAt === "string" &&
|
||||
typeof p.webUrl === "string" &&
|
||||
typeof p.defaultBranch === "string",
|
||||
),
|
||||
JSON.stringify(repos.json ?? null),
|
||||
);
|
||||
r.check(
|
||||
"repos sorted by lastActivityAt desc (daemon-side sort)",
|
||||
repos.json?.[0]?.path === "lvmh/alpha" &&
|
||||
repos.json?.[1]?.path === "lvmh/beta" &&
|
||||
repos.json?.[0]?.defaultBranch === "trunk",
|
||||
JSON.stringify((repos.json ?? []).map((p) => p.path)),
|
||||
);
|
||||
|
||||
const leaky = [connect.text, status.text, repos.text].filter((t) => t.includes(gitlab.pat));
|
||||
r.check("PAT never appears in any daemon response", leaky.length === 0, `leaked in ${leaky.length} response(s)`);
|
||||
const leaky = [connect.text, status.text, repos.text].filter((t) =>
|
||||
t.includes(gitlab.pat),
|
||||
);
|
||||
r.check(
|
||||
"PAT never appears in any daemon response",
|
||||
leaky.length === 0,
|
||||
`leaked in ${leaky.length} response(s)`,
|
||||
);
|
||||
|
||||
const badConnect = await rest(base, token, "/api/gitlab/connect", {
|
||||
method: "POST",
|
||||
body: { token: "glpat-wrong" },
|
||||
});
|
||||
r.check("connect with bad PAT → error status", badConnect.status >= 400, `got ${badConnect.status}`);
|
||||
const statusAfter = await rest(base, token, "/api/gitlab/status");
|
||||
r.check(
|
||||
"failed connect does not clobber the stored PAT",
|
||||
statusAfter.json?.connected === true && statusAfter.json?.username === "e2e-user",
|
||||
JSON.stringify(statusAfter.json),
|
||||
);
|
||||
const badConnect = await rest(base, token, "/api/gitlab/connect", {
|
||||
method: "POST",
|
||||
body: { token: "glpat-wrong" },
|
||||
});
|
||||
r.check(
|
||||
"connect with bad PAT → error status",
|
||||
badConnect.status >= 400,
|
||||
`got ${badConnect.status}`,
|
||||
);
|
||||
const statusAfter = await rest(base, token, "/api/gitlab/status");
|
||||
r.check(
|
||||
"failed connect does not clobber the stored PAT",
|
||||
statusAfter.json?.connected === true &&
|
||||
statusAfter.json?.username === "e2e-user",
|
||||
JSON.stringify(statusAfter.json),
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user