Skip to content

Commit

Permalink
Merge pull request #77 from joshjohanning/organization-scripts
Browse files Browse the repository at this point in the history
Add/update organization reconnaissance scripts
  • Loading branch information
joshjohanning committed May 17, 2024
2 parents 931c578 + cfdead4 commit 5d63e5f
Show file tree
Hide file tree
Showing 11 changed files with 461 additions and 71 deletions.
32 changes: 29 additions & 3 deletions gh-cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -791,22 +791,48 @@ Gets a team
### get-organization-webhooks.sh
Gets a list of webhooks in an organization
Gets a list of webhooks (and webhook information) in an organization
> [!NOTE]
> Requires a GitHub PAT instead of using the OAuth token with the `gh api` command - the OAuth token can only retrieve webhooks it created
### get-organizations-apps-count.sh
Gets the count of apps in all organizations in a given enterprise
### get-organizations-apps.sh
Gets a list of apps (and app information) in all organizations in a given enterprise
### get-organizations-codeowner-usage.sh
Gets the usage of CODEOWNERS files in all repositories in all organizations in a given enterprise (checks `HEAD` for `./`, `./.github`, and `./docs` and returns `TRUE` or `FALSE` for each repository)
### get-organizations-discussions-count.sh
Gets the usage of discussions in all repositories in all organizations in a given enterprise (org-wide discussions have to be created in a repository, so this covers that as well)
### get-organizations-for-user.sh
Gets the list of organizations a user is a member of. This only returns organizations accessible to the person running the script, i.e.: organizations they are also a member of, or public organizations
### get-organizations-projects-count-classic.sh
Gets the count of organization projects (classic projects) in all organizations in a given enterprise
### get-organizations-projects-count.sh
Gets the count of projects (ProjectsV2) in all organizations in a given enterprise
### get-organizations-webhooks-in-enterprise.sh
### get-organizations-settings.sh
Gets the settings for all organizations in an enterprise
### get-organizations-webhooks.sh
Gets a list of webhooks in all organizations in an enterprise
Gets a list of webhooks (and webhook information) in all organizations in an enterprise
> [!NOTE]
> Requires a GitHub PAT instead of using the OAuth token with the `gh api` - the OAuth token can only retrieve webhooks it created
Expand Down
28 changes: 19 additions & 9 deletions gh-cli/get-organization-webhooks.sh
Original file line number Diff line number Diff line change
@@ -1,25 +1,35 @@
#!/bin/bash

# gets information for all webhooks for in an organization

# need: `gh auth login -h github.com` and auth with a PAT!
# since the Oauth token can only receive results for hooks it created for this API call

if [ $# -lt 1 ]
then
echo "usage: $0 <org> <format: tsv|json>" > output.csv/json
echo "usage: $0 <org> <hostname> <format: tsv|json> > output.tsv/json"
exit 1
fi

# need: `gh auth login -h github.com` and auth with a PAT!
# sine the Oauth token can only receive results for hooks it created for this API call
org=$1
hostname=$2
format=$3
export PAGER=""

auth_status=$(gh auth token 2>&1)
# set hostname to github.com by default
if [ -z "$hostname" ]
then
hostname="github.com"
fi

auth_status=$(gh auth token -h $hostname 2>&1)

if [[ $auth_status == gho_* ]]
then
echo "Token starts with gho_ - use "gh auth login" and authenticate with a PAT with read:org and admin:org_hook scope"
exit 1
fi

export PAGER=""
org=$1
format=$2
if [ -z "$format" ]
then
format="tsv"
Expand All @@ -30,7 +40,7 @@ if [ "$format" == "tsv" ]; then
fi

if [ "$format" == "tsv" ]; then
gh api "orgs/$org/hooks" --paginate | jq -r --arg org "$org" '.[] | [$org,.active,.config.url, .created_at, .updated_at, (.events | join(","))] | @tsv'
gh api "orgs/$org/hooks" --hostname $hostname --paginate --jq ".[] | [\"$org\",.active,.config.url, .created_at, .updated_at, (.events | join(\",\"))] | @tsv"
else
gh api "orgs/$org/hooks" --paginate | jq -r --arg org "$org" '.[] | {organization: $org, active: .active, url: .config.url, created_at: .created_at, updated_at: .updated_at, events: .events}'
gh api "orgs/$org/hooks" --hostname $hostname --paginate --jq ".[] | {organization: \"$org\", active: .active, url: .config.url, created_at: .created_at, updated_at: .updated_at, events: .events}"
fi
47 changes: 47 additions & 0 deletions gh-cli/get-organizations-apps-count.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#!/bin/bash

# gets the settings for all organizations in an enterprise

# need: `gh auth refresh -h github.com -s read:org -s read:enterprise`

# note: tsv is the default format
# tsv is a subset of fields, json is all fields

if [ $# -lt 1 ]
then
echo "usage: $0 <enterprise-slug> <hostname> > output.tsv"
exit 1
fi

export PAGER=""
enterpriseslug=$1
hostname=$2

# set hostname to github.com by default
if [ -z "$hostname" ]
then
hostname="github.com"
fi

organizations=$(gh api graphql --paginate --hostname $hostname -f enterpriseName="$enterpriseslug" -f query='
query getEnterpriseOrganizations($enterpriseName: String! $endCursor: String) {
enterprise(slug: $enterpriseName) {
organizations(first: 100, after: $endCursor) {
nodes {
id
login
}
pageInfo {
endCursor
hasNextPage
}
}
}
}' --jq '.data.enterprise.organizations.nodes[].login')

echo -e "Org\tApp Count"

for org in $organizations
do
gh api "orgs/$org/installations" --hostname $hostname --jq ". | [\"$org\", .total_count] | @tsv"
done
59 changes: 59 additions & 0 deletions gh-cli/get-organizations-apps.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
#!/bin/bash

# gets the settings for all organizations in an enterprise

# need: `gh auth refresh -h github.com -s read:org -s read:enterprise`

# note: tsv is the default format
# tsv is a subset of fields, json is all fields

if [ $# -lt 1 ]
then
echo "usage: $0 <enterprise-slug> <hostname> <format: tsv|json> > output.tsv"
exit 1
fi

enterpriseslug=$1
hostname=$2
format=$3
export PAGER=""

# set hostname to github.com by default
if [ -z "$hostname" ]
then
hostname="github.com"
fi

if [ -z "$format" ]
then
format="tsv"
fi

organizations=$(gh api graphql --paginate --hostname $hostname -f enterpriseName="$enterpriseslug" -f query='
query getEnterpriseOrganizations($enterpriseName: String! $endCursor: String) {
enterprise(slug: $enterpriseName) {
organizations(first: 100, after: $endCursor) {
nodes {
id
login
}
pageInfo {
endCursor
hasNextPage
}
}
}
}' --jq '.data.enterprise.organizations.nodes[].login')

if [ "$format" == "tsv" ]; then
echo -e "Org\tApp Slug\tApp ID\tCreated At\tUpdated At\tPermissions\tEvents"
fi

for org in $organizations
do
if [ "$format" == "tsv" ]; then
gh api "orgs/$org/installations" --hostname $hostname --jq ".installations[] | [\"$org\", .app_slug, .app_id, .created_at, .updated_at, (.permissions | join(\",\")), (if .events | length == 0 then \"null\" else .events | join(\",\") end)] | @tsv"
else
gh api "orgs/$org/installations" --hostname $hostname --jq '.installations[]'
fi
done
72 changes: 72 additions & 0 deletions gh-cli/get-organizations-codeowner-usage.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
#!/bin/bash

# gets the discussions count for all organizations in an enterprise

# need: `gh auth refresh -h github.com -s read:org -s read:enterprise`

if [ $# -lt 1 ]; then
echo "usage: $0 <enterprise slug> <hostname> > output.tsv"
exit 1
fi

enterprise=$1
hostname=$2
export PAGER=""

# set hostname to github.com by default
if [ -z "$hostname" ]
then
hostname="github.com"
fi

echo -e "Repository\tUses Codeowners"

# we can't do everything in a single call b/c we need to paginate orgs and then paginate repos in the next query (can't do double pagination with gh api)
organizations=$(gh api graphql --paginate --hostname $hostname -f enterpriseName="$enterprise" -f query='
query getEnterpriseOrganizations($enterpriseName: String! $endCursor: String) {
enterprise(slug: $enterpriseName) {
organizations(first: 100, after: $endCursor) {
nodes {
id
login
}
pageInfo {
endCursor
hasNextPage
}
}
}
}' --jq '.data.enterprise.organizations.nodes[].login')

for org in $organizations
do
gh api graphql --paginate --hostname $hostname -f orgName="$org" -f query='
query getOrganizationRepositories($orgName: String! $endCursor: String) {
organization(login: $orgName) {
repositories(first: 100, after: $endCursor) {
nodes {
nameWithOwner
root: object(expression: "HEAD:CODEOWNERS") {
... on Blob {
text
}
}
github: object(expression: "HEAD:.github/CODEOWNERS") {
... on Blob {
text
}
}
docs: object(expression: "HEAD:docs/CODEOWNERS") {
... on Blob {
text
}
}
}
pageInfo {
endCursor
hasNextPage
}
}
}
}' --jq '.data.organization.repositories.nodes[] | {nameWithOwner: .nameWithOwner, hasCodeowners: if .root.text or .github.text or .docs.text then "TRUE" else "FALSE" end} | [.nameWithOwner, .hasCodeowners] | @tsv'
done
60 changes: 60 additions & 0 deletions gh-cli/get-organizations-discussions-count.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#!/bin/bash

# gets the discussions count for all organizations in an enterprise

# need: `gh auth refresh -h github.com -s read:org -s read:enterprise`

if [ $# -lt 1 ]; then
echo "usage: $0 <enterprise slug> <hostname> > output.tsv"
exit 1
fi

enterprise=$1
hostname=$2
export PAGER=""

# set hostname to github.com by default
if [ -z "$hostname" ]
then
hostname="github.com"
fi

echo -e "Repository\tDiscussion Count"

# we can't do everything in a single call b/c we need to paginate orgs and then paginate repos in the next query (can't do double pagination with gh api)
organizations=$(gh api graphql --paginate --hostname $hostname -f enterpriseName="$enterprise" -f query='
query getEnterpriseOrganizations($enterpriseName: String! $endCursor: String) {
enterprise(slug: $enterpriseName) {
organizations(first: 100, after: $endCursor) {
nodes {
id
login
}
pageInfo {
endCursor
hasNextPage
}
}
}
}' --jq '.data.enterprise.organizations.nodes[].login')

for org in $organizations
do
gh api graphql --paginate --hostname $hostname -f orgName="$org" -f query='
query getOrganizationRepositories($orgName: String! $endCursor: String) {
organization(login: $orgName) {
repositories(first: 100, after: $endCursor) {
nodes {
nameWithOwner
discussions {
totalCount
}
}
pageInfo {
endCursor
hasNextPage
}
}
}
}' --jq '.data.organization.repositories.nodes[] | [.nameWithOwner, .discussions.totalCount] | @tsv'
done
34 changes: 34 additions & 0 deletions gh-cli/get-organizations-projects-count-classic.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#!/bin/bash

# gets the projects count (classic) for all organizations in an enterprise

# need: `gh auth refresh -h github.com -s read:org -s read:enterprise`

if [ $# -lt 1 ]; then
echo "usage: $0 <enterprise slug> <hostname> > output.tsv"
exit 1
fi

enterprise=$1
hostname=$2
export PAGER=""

# set hostname to github.com by default
if [ -z "$hostname" ]
then
hostname="github.com"
fi

echo -e "Organization\tProjects Count (classic)"

gh api graphql -f enterprise="$enterprise" --paginate --hostname $hostname -f query='query($enterprise:String!, $endCursor: String) {
enterprise(slug:$enterprise) {
organizations(first:100, after: $endCursor) {
pageInfo { hasNextPage endCursor }
nodes {
name
projects { totalCount }
}
}
}
}' --jq '.data.enterprise.organizations.nodes[] | [.name, .projects.totalCount] | @tsv'

0 comments on commit 5d63e5f

Please sign in to comment.