Skip to content

Commit

Permalink
Merge pull request #95 from snyk/feat/graphql-queries
Browse files Browse the repository at this point in the history
feat: allow graphql queries to pass through the broker
  • Loading branch information
aviadatsnyk authored Dec 20, 2017
2 parents 6b733fd + b081c50 commit baf44d1
Show file tree
Hide file tree
Showing 6 changed files with 139 additions and 4 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@
.nyc_output
coverage
/test/fixtures/certs/tmp
accept.json
4 changes: 4 additions & 0 deletions client-templates/github/.env.sample
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ GITHUB=
# changed to "api.github.com"
GITHUB_API=$GITHUB/api/v3

# the url that the github graphql API should be accessed at.
# For github.com this should be changed to "api.github.com/graphql"
GITHUB_GRAPHQL=$GITHUB/api/graphql

# the url of your broker client (including scheme and port)
# BROKER_CLIENT_URL=

Expand Down
13 changes: 13 additions & 0 deletions client-templates/github/accept.json.sample
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,19 @@
"method": "PATCH",
"path": "/repos/:name/:repo/git/refs/heads/:ref",
"origin": "https://${GITHUB_TOKEN}@${GITHUB_API}"
},
{
"//": "query graphql",
"method": "POST",
"path": "/graphql",
"origin": "https://${GITHUB_TOKEN}@${GITHUB_GRAPHQL}",
"valid": [
{
"//": "query for all the file names 2 levels deep in the repo. used for auto project detection",
"path": "query",
"regex": "{\\s*repositoryOwner\\(login:\\s*\"([a-zA-Z0-9-_.]+)\"\\)\\s*{\\s*repository\\(name:\\s*\"([a-zA-Z0-9-_.]+)\"\\)\\s*{\\s*object\\(expression:\\s*\"([^\"{}]+)\"\\)\\s*{\\s*\\.\\.\\.\\s*on\\s+Tree\\s+{\\s*entries\\s*{\\s*name\\s+type\\s+object\\s*{\\s*\\.\\.\\.\\s*on\\s+Tree\\s+{\\s*entries\\s*{\\s*name\\s+type\\s+object\\s*{\\s*\\.\\.\\.on\\s+Tree\\s*{\\s*entries\\s*{\\s*name\\s+type\\s*}\\s*}\\s*}\\s*}\\s*}\\s*}\\s*}\\s*}\\s*}\\s*}\\s*}\\s*}"
}
]
}
]
}
25 changes: 22 additions & 3 deletions lib/filters/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ module.exports = ruleSource => {
method = (method || 'get').toLowerCase();
valid = valid || [];

const bodyFilters = valid.filter(v => !!v.path);
const bodyFilters = valid.filter(v => !!v.path && !v.regex);
const bodyRegexFilters = valid.filter(v => !!v.path && !!v.regex);
const queryFilters = valid.filter(v => !!v.queryParam);

// now track if there's any values that we need to interpolate later
Expand Down Expand Up @@ -82,18 +83,36 @@ module.exports = ruleSource => {
}

// if validity filters are present, at least one must be satisfied
if (bodyFilters.length || queryFilters.length) {
if (bodyFilters.length || bodyRegexFilters.length ||
queryFilters.length) {
let isValid;

let parsedBody;
if (bodyFilters.length) {
const parsedBody = tryJSONParse(req.body);
parsedBody = tryJSONParse(req.body);

// validate against the body
isValid = bodyFilters.some(({ path, value }) => {
return undefsafe(parsedBody, path, value);
});
}

if (!isValid && bodyRegexFilters.length) {
parsedBody = parsedBody || tryJSONParse(req.body);

// validate against the body by regex
isValid = bodyRegexFilters.some(({ path, regex }) => {
try {
const re = new RegExp(regex);
return re.test(undefsafe(parsedBody, path));
} catch (err) {
logger.error({err, path, regex},
'failed to test regex rule');
return false;
}
});
}

// no need to check query filters if the request is already valid
if (!isValid && queryFilters.length) {
const parsedQuerystring = qs.parse(querystring);
Expand Down
17 changes: 17 additions & 0 deletions test/fixtures/relay.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,5 +63,22 @@
"value": ".snyk"
}
]
},
{
"//": "used to filter only the wanted graphql query",
"method": "POST",
"path": "/graphql",
"valid": [
{
"//": "malformed regex does not break other filters",
"path": "query",
"regex": "INVALID regex ("
},
{
"//": "query for all the file names 2 levels deep in the repo. used for auto project detection",
"path": "query",
"regex": "{\\s*repositoryOwner\\(login:\\s*\"([a-zA-Z0-9-_.]+)\"\\)\\s*{\\s*repository\\(name:\\s*\"([a-zA-Z0-9-_.]+)\"\\)\\s*{\\s*object\\(expression:\\s*\"([^\"{}]+)\"\\)\\s*{\\s*\\.\\.\\.\\s*on\\s+Tree\\s+{\\s*entries\\s*{\\s*name\\s+type\\s+object\\s*{\\s*\\.\\.\\.\\s*on\\s+Tree\\s+{\\s*entries\\s*{\\s*name\\s+type\\s+object\\s*{\\s*\\.\\.\\.on\\s+Tree\\s*{\\s*entries\\s*{\\s*name\\s+type\\s*}\\s*}\\s*}\\s*}\\s*}\\s*}\\s*}\\s*}\\s*}\\s*}\\s*}\\s*}"
}
]
}
]
83 changes: 82 additions & 1 deletion test/unit/filters.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ const jsonBuffer = (body) => Buffer.from(JSON.stringify(body));
test('filter on body', t => {
const filter = Filters(require(__dirname + '/../fixtures/relay.json'));

t.plan(9);
t.plan(14);
t.pass('filters loaded');

filter({
Expand Down Expand Up @@ -71,6 +71,87 @@ test('filter on body', t => {
t.equal(res, undefined, 'no follow allowed');
});

filter({
url: '/graphql',
method: 'POST',
body: jsonBuffer({
query: `{
repositoryOwner(login: "_REPO_OWNER_") {
repository(name: "_REPO_NAME_") {
object(expression: "_BRANCH_/_NAME_") {
... on Tree {
entries {
name
type
object {
... on Tree {
entries {
name
type
object {
...on Tree {
entries {
name
type
}
}
}
}
}
}
}
}
}
}
}
}`,
})
}, (error, res) => {
t.equal(error, null, 'no error');
t.equal(res, '/graphql', 'allows the path request');
});

filter({
url: '/graphql',
method: 'POST',
body: jsonBuffer({
// "NoSQL injection"
query: `{
repositoryOwner(login: "search: "{\"username\": {\"$regex\": \"sue\"}, \"email\": {\"$regex\": \"sue\"}}"") {
repository(name: "_REPO_NAME_") {
object(expression: "_BRANCH_/_NAME_") {
... on Tree {
entries {
name
type
object {
... on Tree {
entries {
name
type
object {
...on Tree {
entries {
name
type
}
}
}
}
}
}
}
}
}
}
}
}`,
})
}, (error, res) => {
t.ok(error, 'got an error');
t.equal(error.message, 'blocked', 'has been blocked');
t.equal(res, undefined, 'no follow allowed');
});
});

test('filter on querystring', t => {
Expand Down

0 comments on commit baf44d1

Please sign in to comment.