Skip to content

Commit 622db6f

Browse files
authored
Prevent cli from sending git credentials (#1988)
1 parent cf998a6 commit 622db6f

5 files changed

Lines changed: 112 additions & 12 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
## Upcoming
44

55
- `apollo`
6-
- <First `apollo` related entry goes here>
6+
- Prevent cli from sending some git credentials [#1988](https://github.com/apollographql/apollo-tooling/pull/1988)
77
- `apollo-codegen-flow`
88
- <First `apollo-codegen-flow` related entry goes here>
99
- `apollo-codegen-scala`

package-lock.json

Lines changed: 3 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/apollo/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
"gaze": "1.1.3",
5555
"git-parse": "1.0.4",
5656
"git-rev-sync": "2.0.0",
57+
"git-url-parse": "^11.1.2",
5758
"glob": "7.1.5",
5859
"graphql": "14.0.2 - 14.2.0 || ^14.3.1",
5960
"graphql-tag": "2.10.3",

packages/apollo/src/__tests__/git.test.ts

Lines changed: 76 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { gitInfo } from "../git";
1+
import { gitInfo, sanitizeGitRemote } from "../git";
22

33
describe("Git integration", () => {
44
it("Returns commit, branch, message, committer, and remoteUrl", async () => {
@@ -17,3 +17,78 @@ describe("Git integration", () => {
1717
expect(info.branch).toBeDefined();
1818
});
1919
});
20+
21+
describe("strip usernames/passwords from git remotes", () => {
22+
it("returns empty for unknown remotes", () => {
23+
let clean = sanitizeGitRemote("https://un@gitlab.com/apollographql/test");
24+
expect(clean).toBeNull();
25+
});
26+
it("removes username from remote with only a username present", () => {
27+
let clean = sanitizeGitRemote(
28+
"https://un@bitbucket.com/apollographql/test"
29+
);
30+
expect(clean).toEqual("https://REDACTED@bitbucket.com/apollographql/test");
31+
});
32+
it("does not mind case", () => {
33+
let clean = sanitizeGitRemote("https://un@GITHUB.com/apollographql/test");
34+
expect(clean).toEqual("https://REDACTED@GITHUB.com/apollographql/test");
35+
});
36+
it("strips usernames from ssh urls", () => {
37+
let clean = sanitizeGitRemote("ssh://un%401@github.com/apollographql/test");
38+
expect(clean).toEqual("REDACTED@github.com:apollographql/test");
39+
});
40+
it("works properly with (allowed) special characters in username/password", () => {
41+
let clean = sanitizeGitRemote(
42+
"https://un:p%40ssw%3Ard@github.com/apollographql/test"
43+
);
44+
expect(clean).toEqual("https://REDACTED@github.com/apollographql/test");
45+
46+
let bbClean = sanitizeGitRemote(
47+
"https://un:p%40ssw%3Ard@bitbucket.com/apollographql/test"
48+
);
49+
expect(bbClean).toEqual(
50+
"https://REDACTED@bitbucket.com/apollographql/test"
51+
);
52+
});
53+
it("works with non-url remotes from github with git user ONLY", () => {
54+
let clean = sanitizeGitRemote(
55+
"git@github.com:apollographql/apollo-tooling.git"
56+
);
57+
expect(clean).toEqual("git@github.com:apollographql/apollo-tooling.git");
58+
59+
let clean2 = sanitizeGitRemote(
60+
"bob@github.com:apollographql/apollo-tooling.git"
61+
);
62+
expect(clean2).toEqual(
63+
"REDACTED@github.com:apollographql/apollo-tooling.git"
64+
);
65+
});
66+
it("works with non-url remotes from bitbucket with git user ONLY", () => {
67+
let clean = sanitizeGitRemote(
68+
"git@bitbucket.com:apollographql/apollo-tooling.git"
69+
);
70+
expect(clean).toEqual("git@bitbucket.com:apollographql/apollo-tooling.git");
71+
72+
let clean2 = sanitizeGitRemote(
73+
"bob@bitbucket.com:apollographql/apollo-tooling.git"
74+
);
75+
expect(clean2).toEqual(
76+
"REDACTED@bitbucket.com:apollographql/apollo-tooling.git"
77+
);
78+
});
79+
it("does not allow non-url remotes from unrecognized providers (not github)", () => {
80+
let clean = sanitizeGitRemote(
81+
"git@lab.com:apollographql/apollo-tooling.git"
82+
);
83+
expect(clean).toBeNull();
84+
});
85+
// TODO maybe fix this in the future?
86+
// git-url-parse right now just uses the dirty `href` if the protocol is unknow
87+
// https://github.com/IonicaBizau/git-url-parse/blob/master/lib/index.js#L216-L217
88+
it("returns null with unknown protocols", () => {
89+
let clean = sanitizeGitRemote(
90+
"git+http://un:p%40sswrd@github.com/apollographql/test"
91+
);
92+
expect(clean).toBeNull();
93+
});
94+
});

packages/apollo/src/git.ts

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import git from "git-rev-sync";
66
import pickBy from "lodash.pickby";
77
import identity from "lodash.identity";
88
import Command from "@oclif/command";
9+
import gitUrlParse from "git-url-parse";
910

1011
const findGitRoot = (start?: string | string[]): string | void => {
1112
start = start || process.cwd();
@@ -23,6 +24,35 @@ const findGitRoot = (start?: string | string[]): string | void => {
2324
}
2425
};
2526

27+
/**
28+
* remove any username and password info from the
29+
* git remote (`git ls-remote --get-url`)
30+
*
31+
* This can be made more generic in the future, allowing for more options
32+
* for git providers. right now, we only support github & bitbucket. other remotes
33+
* serve no purpose currently in graph manager.
34+
*/
35+
36+
export const sanitizeGitRemote = (remote?: string) => {
37+
if (!remote) return null;
38+
const info = gitUrlParse(remote);
39+
40+
// we only support github and bitbucket sources
41+
const source = info.source.toLowerCase();
42+
if (source !== "github.com" && source !== "bitbucket.com") return null;
43+
44+
if (info.user !== "" && info.user !== "git") {
45+
info.user = "REDACTED";
46+
}
47+
48+
// just to make sure that with an unknown `protocol` that stringify doesn't
49+
// just print the old, dirty url
50+
// https://github.com/IonicaBizau/git-url-parse/blob/0b362b3e3b91a23ae58355fd2160523f0abde5d9/lib/index.js#L216-L217
51+
info.href = null;
52+
53+
return gitUrlParse.stringify(info);
54+
};
55+
2656
export interface Commit {
2757
authorName: string | null;
2858
authorEmail: string | null;
@@ -71,7 +101,7 @@ export const gitInfo = async (
71101
// The remoteUrl call can fail and throw an error
72102
// https://github.com/kurttheviking/git-rev-sync-js#gitremoteurl--string
73103
try {
74-
remoteUrl = git.remoteUrl();
104+
remoteUrl = sanitizeGitRemote(git.remoteUrl());
75105
} catch (e) {
76106
log(["Unable to retrieve remote url, failed with:", e].join("\n\n"));
77107
}

0 commit comments

Comments
 (0)