Github V4 GraphQL API - audit log query - github

i'm trying to interact with github api v4, i want to query audit log events based on schemas available in the api. I can found a documentary about the github api here and I can see the schemas available here but there are no working examples of how to query the different schemas.
If there is someone here experience with this API, specially with the audit log schemas, I need a working example to start interacting with the audit log schemas...
for example i want to query all organization add member to team events, suppose to be in the schema TeamAddMemberAuditEntry, or remove member from org OrgRemoveMemberAuditEntry
So far I've tried to query it with node.js:
require('isomorphic-fetch');
fetch('https://api.github.com/graphql', {
method: 'POST',
headers: { 'Content-Type': 'application/json',
'Authorization': 'bearer <token>',
'Accept': 'application/vnd.github.audit-log- preview+json'},
body: JSON.stringify({ query: '{ TeamAddMemberAuditEntry }' }),
})
.then(res => res.json())
.then(res => console.log(res.data));

If someone here will look for solution, after viewing the public schema this is how the query looks for getting audit-log objects, this is without the headers and the query prefix of course.
The auditLog is a union type, you can get multiple audit events by adding another "...on" block. for example here i'm getting all the orginvitemembers events
{
organization(login:"<your-org>") {
auditLog(first:2) {
edges {
node {
__typename
... on OrgInviteMemberAuditEntry {
action
actorIp
actorLogin
createdAt
userLogin
actorLocation{
country
city
}
}
}
}
}
}
}

I was after the same thing. I think your query statement is like the issue.
I came across this documentation in the GitHub blog.
https://github.blog/2019-06-21-the-github-enterprise-audit-log-api-for-graphql-beginners/
I was able to adapt the example query and come up with the following...
{
organization(login: "xyz-corp") {
auditLog(last: 10
, query: "action:org.remove_member") {
edges {
node {
... on AuditEntry {
action
actorLogin
userLogin
createdAt
user{
name
email
}
}
}
}
}
}
}
I was able to substitute the query with the following just as I would via the UI to get adds and updates.
action:org.add_member
action:org.update_member
Other audit log query items are described here
https://docs.github.com/en/organizations/keeping-your-organization-secure/reviewing-the-audit-log-for-your-organization

Related

Pagination on reactionGroups in the GitHub GraphQL API

I’m trying to extract the username of all the users that have reacted to an issue (and how they reacted) with the GitHub GraphQL API. I’ve only been able to extract a maximum of 11 users per reaction group per query, and I haven’t found a way to successfully paginate the queries - the same users are returned each time.
Here’s an example of my query using an issue with many reactions:
{
repository(owner: "mapbox", name: "mapbox-gl-js") {
issue(number: 3184) {
reactionGroups {
content
reactors(first: 30) {
totalCount
pageInfo {
hasNextPage
endCursor
}
edges {
node {
... on User {
login
}
}
}
}
}
}
}
}
For THUMBS_UP reactions this correctly returns totalCount: 77. However, there are only 11 usernames returned (not the 30 requested). The value of hasNextPage in pageInfo is false, and using the returned cursor value or modifying the reactors query to last:30 instead of first:30 has no impact on which 11 users are returned.
Is there a way I can modify my query to get this working (I’m new to GraphQL) or is this a current limitation of the API? Thanks!
(I've also asked this on the GitHub community forums, but no reply yet - see here)

Get info about several repositories from Github Graphql API in a single call

I am trying to create a query to Github GraphQL API that receive a list of repos as a parameter, and returns the info of those repositories in a single API call, does anyone know how to do that?
Something like this (I know this doesn't work)
query myOrgRepos($repos: [String!]!) {
search(query:"""
repo in $repos
""", type: REPOSITORY, first: 100) {
repo: nodes {
... on Repository{
name
description
updatedAt
}
}
}
It took me some time to understand your comment so I will post the answer in full. The key is to use Github's advanced search “syntax” in the query string, see here for examples.
The following query will find all repositories of user “github” as well as the graphql-js repository of user “graphql”:
query {
search(query: "user:github repo:graphql/graphql-js" type: REPOSITORY first: 10) {
nodes {
... on Repository {
name
description
updatedAt
}
}
}
}
My understanding of your question is that you want to input a list of "known" repos and output information about them. In this case you can form a query of the following type.
{
nodes(ids: ["node_id_1", "node_id_2"]) {
... on Repository {
nameWithOwner
createdAt
}
}
}
Here the ids are the node_ids of the repositories you are interested in. You can obtain these by individual GraphQL calls as follows
{
repository(owner: "owner", name: "name") {
id
}
}

How to get info about specific user using github graphQL?

How can I get info about specific user or specific repo using github GraphQL? I've try this query:
{
search (query: "torvalds", type: USER, first: 1){
edges {
node {
}
}
}
}
but autocomplete for node show only __typename which return string "User".
DEMO
search returns a SearchResultItem, which is an interface. In order to access fields on it, you need to use a fragment on a concrete type like so:
{
search (query: "torvalds", type: USER, first: 1){
edges {
node {
... on User {
login
}
}
}
}
}
I made a short video tour of GitHub's GraphQL API which you might find useful: https://youtu.be/6xO87LlijoQ
EDIT: If you're just looking for a user or org and know the exact name, #stubailo's answer is actually better. You'll still need to use a fragment for most fields, but you'll get just one result of type RepositoryOwner.
The best way to get information about a specific user is to use the repositoryOwner query, like so:
{
repositoryOwner(login: "stubailo") {
login
... on User {
bio
}
}
}
Search is good too, but if you know the name of a user or organization, it's more direct to use the query above.

An attempt on making REST API for nested attribute using Restivus

So, I'm trying to show how Restivus API works and Meteor is nice to my colleagues. :)
I've made a simple blog app at http://askar-blog.meteor.com/ (thanks to DiscoverMeteor book).
My repo https://github.com/tenzan/blog
(I'm reading https://github.com/kahmali/meteor-restivus#restivus)
I have three collections:
users
posts
comments
So, post has many comments. Usually, we used to have comments as a nested documents inside of a post, but from the Meteor's nature these two attributes are split up into different collections.
I want to implement a REST API, so that I can access (including CRUD operations) posts and collections in the way:
http://example.com/api/posts - all posts
http://example.com/api/posts/post_id - a specific post
http://example.com/api/posts/post_id/comments - all comments that belongs to a given post
http://example.com/api/posts/post_id/comments/comment_id - a specific comment that belongs to a given post
If you have a look at my repo, you will see there're posts.js and comments.js under lib/collections.
As I understood, to enable REST API, I will need the following snippet in the posts.js:
if (Meteor.isServer) {
// Global API configuration
var Api = new Restivus({
useDefaultAuth: true,
prettyJson: true
});
// Generates: GET, POST on /api/post and GET, PUT, DELETE on
// /api/items/:id for the Posts collection
Api.addCollection(Posts);
// Generates: POST on /api/users and GET, DELETE /api/users/:id for
// Meteor.users collection
Api.addCollection(Meteor.users, {
excludedEndpoints: ['getAll', 'put'],
routeOptions: {
authRequired: true
},
endpoints: {
post: {
authRequired: false
},
delete: {
roleRequired: 'admin'
}
}
});
As you see, I've added Api.addCollection(Posts); and I've confirmed I can access all posts or a specific one.
My questions:
1- How can I setup API to access comments for their parent post?
2 - Will I have to have to following code to access posts ? I'm asking because, I'm already able to access them as I have Api.addCollection(Posts); :
Maps to: /api/posts/:id
Api.addRoute('posts/:id', {authRequired: true}, {
get: function () {
return Posts.findOne(this.urlParams.id);
},
delete: {
roleRequired: ['author', 'admin'],
action: function () {
if (Articles.remove(this.urlParams.id)) {
return {status: 'success', data: {message: 'Post removed'}};
}
return {
statusCode: 404,
body: {status: 'fail', message: 'Post not found'}
};
}
}
});
I apologise, I got confused myself trying to figure out the correct way of making a REST API.
Please feel free to add anything important on this regard I have missed here.
I've discussed with the author of the package
https://github.com/kahmali/meteor-restivus/issues/128
The feature is being developed
https://github.com/kahmali/meteor-restivus/issues/70

Sailsjs and Associations

Getting into sails.js - enjoying the cleanliness of models, routes, and the recent addition of associations. My dilemma:
I have Users, and Groups. There is a many-many relationship between the two.
var User = {
attributes: {
username: 'string',
groups: {
collection: 'group',
via: 'users'
}
}
};
module.exports = User;
...
var Group = {
attributes: {
name: 'string',
users: {
collection: 'user',
via: 'groups',
dominant: true
}
}
};
module.exports = Group;
I'm having difficulty understanding how I would save a user and it's associated groups.
Can I access the 'join table' directly?
From an ajax call, how should I be sending in the list of group ids to my controller?
If via REST URL, is this already accounted for in blueprint functions via update?
If so - what does the URL look like? /user/update/1?groups=1,2,3 ?
Is all of this just not supported yet? Any insight is helpful, thanks.
Documentation for these blueprints is forthcoming, but to link two records that have a many-to-many association, you can use the following REST url:
POST /user/[userId]/groups
where the body of the post is:
{id: [groupId]}
assuming that id is the primary key of the Group model. Starting with v0.10-rc5, you can also simultaneously create and a add a new group to a user by sending data about the new group in the POST body, without an id:
{name: 'myGroup'}
You can currently only add one linked entity at a time.
To add an entity programmatically, use the add method:
User.findOne(123).exec(function(err, user) {
if (err) {return res.serverError(err);}
// Add group with ID 1 to user with ID 123
user.groups.add(1);
// Add brand new group to user with ID 123
user.groups.add({name: 'myGroup'});
// Save the user, committing the additions
user.save(function(err, user) {
if (err) {return res.serverError(err);}
return res.json(user);
});
});
Just to answer your question about accessing the join tables directly,
Yes you can do that if you are using Model.query function. You need to check the namees of the join tables from DB itself. Not sure if it is recommended or not but I have found myself in such situations sometimes when it was unavoidable.
There have been times when the logic I was trying to implement involved a lot many queries and it was required to be executed as an atomic transaction.
In those case, I encapsulated all the DB logic in a stored function and executed that using Model.query
var myQuery = "select some_db_function(" + <param> + ")";
Model.query(myQuery, function(err, result){
if(err) return res.json(err);
else{
result = result.rows[0].some_db_function;
return res.json(result);
}
});
postgres has been a great help here due to json datatype which allowed me to pass params as JSON and also return values as JSON