From e04516df49b2f070db9c4789509f9e738aff9bb3 Mon Sep 17 00:00:00 2001 From: Patrick Lewis <4015312+locus313@users.noreply.github.com> Date: Wed, 5 Aug 2026 12:31:23 -0700 Subject: [PATCH] fix: standardize CSV/report output locations across scripts Several reporting scripts wrote their output inconsistently: some to a 'reports/' subdirectory (with differing CWD- vs script-dir-relative defaults), others to a hardcoded filename in the current directory. - github-copilot-report.sh and github-repo-permissions-report.sh now default their CSV output into $REPORT_DIR (default ./reports, overridable via env var or their existing -o/--output flag). - github-close-archived-repo-security-alerts.sh: renamed the script-local REPORTS_DIR variable to the standard REPORT_DIR, exposed it as an env var/action input, and defaulted it to ./reports to match every other reporting script. - github-archive-old-repos.sh: changed its REPORT_DIR default from a script-directory-relative path to ./reports for consistency with the rest of the fleet (still overridable). - github-get-repo-list.sh: fixed a bug where it silently wrote to ./repo-list.csv in the working directory instead of stdout, despite its own header, README, and action.yml all documenting stdout output. Updated README.md, action.yml inputs, and script header comments to document REPORT_DIR everywhere it now applies. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- README.md | 14 ++++++++++++-- .../github-archive-old-repos.sh | 3 ++- .../action.yml | 5 +++++ .../github-close-archived-repo-security-alerts.sh | 7 ++++--- .../github-get-repo-list/github-get-repo-list.sh | 5 ++--- reporting/github-copilot-report/action.yml | 7 ++++++- .../github-copilot-report/github-copilot-report.sh | 13 +++++++++++-- .../github-repo-permissions-report/action.yml | 5 +++++ .../github-repo-permissions-report.sh | 6 +++++- 9 files changed, 52 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 78054a5..4cfe294 100644 --- a/README.md +++ b/README.md @@ -330,6 +330,7 @@ cd org-admin/github-archive-old-repos | Variable | Description | Default | |----------|-------------|---------| | `YEARS_THRESHOLD` | Age threshold in years | `5` | +| `REPORT_DIR` | Output directory for the CSV report | `./reports` | --- @@ -409,6 +410,7 @@ cd org-admin/github-close-archived-repo-security-alerts | `DEPENDABOT_REASON` | Dismiss reason for Dependabot alerts | `tolerable_risk` | | `CODE_SCANNING_REASON` | Dismiss reason for code scanning alerts | `won't fix` | | `SECRET_SCANNING_RESOLUTION` | Resolution for secret scanning alerts | `wont_fix` | +| `REPORT_DIR` | Output directory for the CSV report | `./reports` | **What it does:** - Enumerates all repositories in the organization @@ -561,7 +563,11 @@ cd reporting/github-repo-permissions-report |------|-------------|----------| | `-r, --repo OWNER/REPO` | Target repository (required) | — | | `-b, --branch NAME` | Branch to evaluate | Repository default branch | -| `-o, --output FILE` | Output CSV path | `OWNER-REPO-permissions-BRANCH-YYYYMMDD.csv` | +| `-o, --output FILE` | Output CSV path | `$REPORT_DIR/OWNER-REPO-permissions-BRANCH-YYYYMMDD.csv` | + +| Variable | Description | Default | +|----------|-------------|---------| +| `REPORT_DIR` | Output directory for the CSV report when `-o/--output` is not given | `./reports` | **What it does:** - Fetches all collaborators and teams with repository access @@ -617,10 +623,14 @@ az login # optional; needed only for Entra ID department enrichment | `-e, --enterprise SLUG` | GitHub Enterprise slug (or `$GITHUB_ENTERPRISE`) | — | | `-d, --upn-domain DOM` | Email domain for Entra lookup when GitHub carries no email (or `$UPN_DOMAIN`) | — | | `--credits N` | Override credits-per-seat value (or `$CREDITS_PER_SEAT_OVERRIDE`) | Auto-detected | -| `--output FILE` | Output CSV filename | `copilot-report-YYYYMMDD.csv` | +| `--output FILE` | Output CSV filename | `$REPORT_DIR/copilot-report-YYYYMMDD.csv` | | `--no-entra` | Skip Entra ID department lookup | — | | `--no-budgets` | Skip per-user AI credit budget lookup (Universal/Individual) | — | +| Variable | Description | Default | +|----------|-------------|---------| +| `REPORT_DIR` | Output directory for the CSV report when `--output` is not given | `./reports` | + **What it does:** - Fetches all Copilot seats across the enterprise (deduplicated by user) - Fetches per-user AI credit consumption for the current billing month diff --git a/org-admin/github-archive-old-repos/github-archive-old-repos.sh b/org-admin/github-archive-old-repos/github-archive-old-repos.sh index 2860895..8548da7 100755 --- a/org-admin/github-archive-old-repos/github-archive-old-repos.sh +++ b/org-admin/github-archive-old-repos/github-archive-old-repos.sh @@ -15,6 +15,7 @@ # GITHUB_TOKEN Required. PAT with repo scope # ORG Required. GitHub organization name # YEARS_THRESHOLD Optional. Age threshold in years (default: 5) +# REPORT_DIR Optional. Output directory for the CSV report (default: ./reports) # API_URL_PREFIX Optional. GitHub API base URL (default: https://api.github.com) # # Requirements: @@ -36,7 +37,7 @@ ORG=${ORG:-''} API_URL_PREFIX=${API_URL_PREFIX:-'https://api.github.com'} YEARS_THRESHOLD=${YEARS_THRESHOLD:-5} TIMESTAMP=$(date +"%Y%m%d_%H%M%S") -REPORT_DIR="${REPORT_DIR:-$(dirname "$0")/reports}" +REPORT_DIR="${REPORT_DIR:-./reports}" REPORT_FILE="${REPORT_DIR}/old_repos_${TIMESTAMP}.csv" TEMP_FILE=$(mktemp) diff --git a/org-admin/github-close-archived-repo-security-alerts/action.yml b/org-admin/github-close-archived-repo-security-alerts/action.yml index 74659b2..a4b3507 100644 --- a/org-admin/github-close-archived-repo-security-alerts/action.yml +++ b/org-admin/github-close-archived-repo-security-alerts/action.yml @@ -31,6 +31,10 @@ inputs: description: 'GitHub API base URL' required: false default: 'https://api.github.com' + report-dir: + description: 'Output directory for the CSV report' + required: false + default: './reports' runs: using: composite steps: @@ -43,6 +47,7 @@ runs: CODE_SCANNING_REASON: ${{ inputs.code-scanning-reason }} SECRET_SCANNING_RESOLUTION: ${{ inputs.secret-scanning-resolution }} API_URL_PREFIX: ${{ inputs.api-url-prefix }} + REPORT_DIR: ${{ inputs.report-dir }} run: | ARGS=(--type "${{ inputs.type }}") [[ "${{ inputs.dry-run }}" == "true" ]] && ARGS+=(--dry-run) diff --git a/org-admin/github-close-archived-repo-security-alerts/github-close-archived-repo-security-alerts.sh b/org-admin/github-close-archived-repo-security-alerts/github-close-archived-repo-security-alerts.sh index 1beef3e..a25fe1c 100755 --- a/org-admin/github-close-archived-repo-security-alerts/github-close-archived-repo-security-alerts.sh +++ b/org-admin/github-close-archived-repo-security-alerts/github-close-archived-repo-security-alerts.sh @@ -21,6 +21,7 @@ # DEPENDABOT_REASON Optional. Dismiss reason for Dependabot alerts (default: tolerable_risk) # CODE_SCANNING_REASON Optional. Dismiss reason for code scanning (default: won't fix) # SECRET_SCANNING_RESOLUTION Optional. Resolution for secret scanning (default: wont_fix) +# REPORT_DIR Optional. Output directory for the CSV report (default: ./reports) # # Requirements: # - curl @@ -40,8 +41,8 @@ GITHUB_TOKEN=${GITHUB_TOKEN:-''} ORG=${ORG:-''} API_URL_PREFIX=${API_URL_PREFIX:-'https://api.github.com'} TIMESTAMP=$(date +"%Y%m%d_%H%M%S") -REPORTS_DIR="$(dirname "$0")/reports" -REPORT_FILE="${REPORTS_DIR}/security_alerts_closed_${TIMESTAMP}.csv" +REPORT_DIR="${REPORT_DIR:-./reports}" +REPORT_FILE="${REPORT_DIR}/security_alerts_closed_${TIMESTAMP}.csv" # Dismiss/resolve reasons — override via env if needed DEPENDABOT_REASON=${DEPENDABOT_REASON:-'tolerable_risk'} # fix_started | inaccurate | no_bandwidth | not_used | tolerable_risk @@ -117,7 +118,7 @@ TOTAL_ERRORS=0 ## CSV REPORT HEADER ### if [ "${DRY_RUN}" = false ]; then - mkdir -p "${REPORTS_DIR}" + mkdir -p "${REPORT_DIR}" echo "timestamp,org,repo,alert_type,alert_number,alert_summary,action" > "${REPORT_FILE}" fi diff --git a/org-admin/github-get-repo-list/github-get-repo-list.sh b/org-admin/github-get-repo-list/github-get-repo-list.sh index b766ff3..1abd87e 100755 --- a/org-admin/github-get-repo-list/github-get-repo-list.sh +++ b/org-admin/github-get-repo-list/github-get-repo-list.sh @@ -75,11 +75,10 @@ process_repos () { printf '%s,%s,%s,%s,%s,"%s",%s,%s,%s,%s\n' \ "${i}" "${REPO_FULLNAME}" "${REPO_OWNER}" "${REPO_PRIVATE}" "${REPO_HTMLURL}" \ - "${ESCAPED_DESCRIPTION}" "${REPO_FORK}" "${REPO_PUSHEDAT}" "${REPO_CREATEDAT}" "${REPO_UPDATEDAT}" \ - >> repo-list.csv + "${ESCAPED_DESCRIPTION}" "${REPO_FORK}" "${REPO_PUSHEDAT}" "${REPO_CREATEDAT}" "${REPO_UPDATEDAT}" done < <(echo "${repos_json}" | jq -r 'sort_by(.name) | .[] | .name') done } -echo "name,full_name,owner,private,html_url,description,fork,pushed_at,created_at,updated_at" > repo-list.csv +echo "name,full_name,owner,private,html_url,description,fork,pushed_at,created_at,updated_at" process_repos diff --git a/reporting/github-copilot-report/action.yml b/reporting/github-copilot-report/action.yml index cc0c09d..3af5d01 100644 --- a/reporting/github-copilot-report/action.yml +++ b/reporting/github-copilot-report/action.yml @@ -20,9 +20,13 @@ inputs: required: false default: '' output: - description: 'Output CSV file path (default: copilot-report-YYYYMMDD.csv)' + description: 'Output CSV file path (default: $REPORT_DIR/copilot-report-YYYYMMDD.csv)' required: false default: '' + report-dir: + description: 'Output directory for the CSV report when output is not given' + required: false + default: './reports' no-entra: description: 'Skip Entra ID department lookup' required: false @@ -42,6 +46,7 @@ runs: UPN_DOMAIN: ${{ inputs.upn-domain }} ENTRA_TENANT: ${{ inputs.entra-tenant }} CREDITS_PER_SEAT_OVERRIDE: ${{ inputs.credits }} + REPORT_DIR: ${{ inputs.report-dir }} run: | ARGS=() [[ -n "${{ inputs.output }}" ]] && ARGS+=(--output "${{ inputs.output }}") diff --git a/reporting/github-copilot-report/github-copilot-report.sh b/reporting/github-copilot-report/github-copilot-report.sh index 5c7c459..c18a9cf 100755 --- a/reporting/github-copilot-report/github-copilot-report.sh +++ b/reporting/github-copilot-report/github-copilot-report.sh @@ -45,6 +45,9 @@ # amount plus an override_budget_id when an Individual budget applies. # Requires the token owner to be an enterprise admin or billing manager. # Use --no-budgets to skip. +# +# REPORT_DIR (optional, default: ./reports) — output directory for the CSV +# report when --output is not given. # ============================================================================= set -euo pipefail @@ -60,7 +63,8 @@ API_URL_PREFIX="${API_URL_PREFIX:-https://api.github.com}" UPN_DOMAIN="${UPN_DOMAIN:-}" ENTRA_TENANT="${ENTRA_TENANT:-}" CREDITS_PER_SEAT_OVERRIDE="${CREDITS_PER_SEAT_OVERRIDE:-}" -OUTPUT_CSV="copilot-report-$(date +%Y%m%d).csv" +REPORT_DIR="${REPORT_DIR:-./reports}" +OUTPUT_CSV="" NO_ENTRA=false NO_BUDGETS=false GRAPH_TOKEN="" @@ -127,7 +131,7 @@ Options: when not set; only needed to override that result. --credits N Override credits-per-seat value (or $CREDITS_PER_SEAT_OVERRIDE) Use if your portal shows a different pool size than expected - --output FILE Output CSV (default: copilot-report-YYYYMMDD.csv) + --output FILE Output CSV (default: $REPORT_DIR/copilot-report-YYYYMMDD.csv) --no-entra Skip Entra ID department lookup --no-budgets Skip per-user AI credit budget lookup (Universal/Individual) -h, --help Show this message @@ -165,6 +169,11 @@ require_command jq require_env_var GITHUB_TOKEN validate_github_token "bearer" +if [[ -z "$OUTPUT_CSV" ]]; then + mkdir -p "$REPORT_DIR" + OUTPUT_CSV="${REPORT_DIR}/copilot-report-$(date +%Y%m%d).csv" +fi + # ── Acquire Microsoft Graph token via az CLI ────────────────────────────────── if [[ "$NO_ENTRA" == "true" ]]; then print_warning "Entra ID lookup disabled (--no-entra). Department column will be N/A." diff --git a/reporting/github-repo-permissions-report/action.yml b/reporting/github-repo-permissions-report/action.yml index e69abe0..199bc0e 100644 --- a/reporting/github-repo-permissions-report/action.yml +++ b/reporting/github-repo-permissions-report/action.yml @@ -15,6 +15,10 @@ inputs: description: 'Output CSV file path' required: false default: '' + report-dir: + description: 'Output directory for the CSV report when output is not given' + required: false + default: './reports' runs: using: composite steps: @@ -22,6 +26,7 @@ runs: shell: bash env: GITHUB_TOKEN: ${{ inputs.github-token || github.token }} + REPORT_DIR: ${{ inputs.report-dir }} run: | ARGS=(-r "${{ inputs.repo }}") [[ -n "${{ inputs.branch }}" ]] && ARGS+=(-b "${{ inputs.branch }}") diff --git a/reporting/github-repo-permissions-report/github-repo-permissions-report.sh b/reporting/github-repo-permissions-report/github-repo-permissions-report.sh index 888b370..5c2f59d 100755 --- a/reporting/github-repo-permissions-report/github-repo-permissions-report.sh +++ b/reporting/github-repo-permissions-report/github-repo-permissions-report.sh @@ -14,6 +14,8 @@ # GITHUB_TOKEN Required. PAT with repo and read:org scope # (or provided automatically from an active gh auth session) # API_URL_PREFIX Optional. GitHub API base URL (default: https://api.github.com) +# REPORT_DIR Optional. Output directory for the CSV report when -o/--output +# is not given (default: ./reports) # # Requirements: # - curl @@ -27,6 +29,7 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" source "${SCRIPT_DIR}/../../lib/github-common.sh" API_URL_PREFIX=${API_URL_PREFIX:-'https://api.github.com'} +REPORT_DIR=${REPORT_DIR:-'./reports'} REPO="" BRANCH="" OUTPUT_CSV="" @@ -104,7 +107,8 @@ if [[ -z "$BRANCH" ]]; then fi if [[ -z "$OUTPUT_CSV" ]]; then - OUTPUT_CSV="${REPO//\//-}-permissions-${BRANCH}-$(date +%Y%m%d).csv" + mkdir -p "$REPORT_DIR" + OUTPUT_CSV="${REPORT_DIR}/${REPO//\//-}-permissions-${BRANCH}-$(date +%Y%m%d).csv" fi print_status "Fetching collaborators..."