feat(git): a CodeCommit SSH key ID is saved for every region; a clone tries each saved account
Settings → Git → AWS CodeCommit asks for the key ID only: the default key's login is written for every CodeCommit region at once (allRegions), shown as one row, with Use in every region for an older one-region save. A clone of a CodeCommit URL with no user tries every saved CodeCommit login — the region's own first, then other regions' and each named key's — so a second AWS account clones from the plain AWS URL with no ssh://<alias>/ rewrite.
This commit is contained in:
@@ -5,7 +5,9 @@
|
||||
* ECREDENTIALS for a remote wanting a login), `/api/me/git` (key made once,
|
||||
* only the public half returned, 0600 on disk; named keys beside the default
|
||||
* ones, SSH logins per alias tied to one key, which a clone then offers
|
||||
* alone; a CodeCommit region with no login borrowing another region's), and the member (S3) path of
|
||||
* alone; a CodeCommit region with no login borrowing another region's; one key ID
|
||||
* saved for every region; a second account's login tried when the region's own is
|
||||
* refused), and the member (S3) path of
|
||||
* `server/lib/git-identity.js` with run-as and git stubbed — what reaches
|
||||
* git's argv, and that a login typed without "remember" leaves the member's
|
||||
* store as it was.
|
||||
@@ -688,6 +690,91 @@ describe("CodeCommit: a region with no login borrows another region's", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("CodeCommit: one key ID for every region", () => {
|
||||
const getUrl = (url) =>
|
||||
execFileSync("git", ["ls-remote", "--get-url", url], { encoding: "utf8" }).trim();
|
||||
const { CODECOMMIT_REGIONS } = require("../lib/git-identity");
|
||||
|
||||
it("saves the default login for every region, and removes it in one go", async () => {
|
||||
const r = await request("PUT", "/api/me/git/ssh-user", {
|
||||
host: "git-codecommit.us-east-1.amazonaws.com",
|
||||
user: "APKAALL",
|
||||
allRegions: true,
|
||||
});
|
||||
assert.equal(r.status, 200, JSON.stringify(r.body));
|
||||
assert.equal(r.body.sshUsers.length, CODECOMMIT_REGIONS.length);
|
||||
assert.deepEqual(r.body.codecommitRegions, CODECOMMIT_REGIONS);
|
||||
for (const region of ["ap-northeast-1", "eu-west-1"]) {
|
||||
const h = `git-codecommit.${region}.amazonaws.com`;
|
||||
assert.equal(getUrl(`ssh://${h}/v1/repos/x`), `ssh://APKAALL@${h}/v1/repos/x`);
|
||||
}
|
||||
// A second every-region save replaces each region's rule, never stacks.
|
||||
const again = await request("PUT", "/api/me/git/ssh-user", {
|
||||
host: "git-codecommit.us-east-1.amazonaws.com",
|
||||
user: "APKAALL2",
|
||||
allRegions: true,
|
||||
});
|
||||
assert.equal(again.body.sshUsers.length, CODECOMMIT_REGIONS.length);
|
||||
assert.ok(again.body.sshUsers.every((u) => u.user === "APKAALL2"));
|
||||
// An alias is never every region's.
|
||||
const bad = await request("PUT", "/api/me/git/ssh-user", {
|
||||
host: "git-codecommit.us-east-1.amazonaws.com",
|
||||
user: "APKAX",
|
||||
alias: "prod",
|
||||
allRegions: true,
|
||||
});
|
||||
assert.equal(bad.status, 400);
|
||||
const del = await request(
|
||||
"DELETE",
|
||||
"/api/me/git/ssh-user/git-codecommit.us-east-1.amazonaws.com?allRegions=1&user=APKAALL2"
|
||||
);
|
||||
assert.equal(del.status, 200);
|
||||
assert.deepEqual(del.body.sshUsers, []);
|
||||
});
|
||||
|
||||
it("tries a second account's login when the region's own is refused", async () => {
|
||||
const bare = path.join(ROOT, "bare.git");
|
||||
const R = "git-codecommit.ap-northeast-1.amazonaws.com";
|
||||
assert.equal(
|
||||
(await request("PUT", "/api/me/git/ssh-user", { host: R, user: "APKAMINE" })).status,
|
||||
200
|
||||
);
|
||||
assert.equal(
|
||||
(
|
||||
await request("PUT", "/api/me/git/ssh-user", {
|
||||
host: "git-codecommit.us-east-1.amazonaws.com",
|
||||
user: "APKAOTHER",
|
||||
alias: "other-acct",
|
||||
})
|
||||
).status,
|
||||
200
|
||||
);
|
||||
const rules = [
|
||||
[`url.file://${ROOT}/nowhere.git.insteadOf`, `ssh://APKAMINE@${R}/v1/repos/r`],
|
||||
[`url.file://${bare}.insteadOf`, `ssh://APKAOTHER@${R}/v1/repos/r`],
|
||||
];
|
||||
for (const [k, v] of rules) execFileSync("git", ["config", "--global", "--add", k, v]);
|
||||
try {
|
||||
const r = await request("POST", "/api/lanes/clone", {
|
||||
url: `ssh://${R}/v1/repos/r`,
|
||||
parent: WORK,
|
||||
name: "second-account",
|
||||
});
|
||||
assert.equal(r.status, 201, JSON.stringify(r.body));
|
||||
const origin = execFileSync(
|
||||
"git",
|
||||
["-C", path.join(WORK, "second-account"), "config", "remote.origin.url"],
|
||||
{ encoding: "utf8" }
|
||||
).trim();
|
||||
assert.equal(origin, `ssh://APKAOTHER@${R}/v1/repos/r`);
|
||||
} finally {
|
||||
for (const [k] of rules) execFileSync("git", ["config", "--global", "--unset-all", k]);
|
||||
await request("DELETE", `/api/me/git/ssh-user/${R}`);
|
||||
await request("DELETE", "/api/me/git/ssh-user/other-acct");
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe("git-identity, member account (S3, stubbed)", () => {
|
||||
const runAs = require("../lib/run-as");
|
||||
const worktree = require("../lib/worktree");
|
||||
|
||||
Reference in New Issue
Block a user