Skip to content
Back to skills

Github Repo Metadata

ASecurity

Use when updating a GitHub repository's description, homepage, topics, or other metadata via the API — especially when the gh CLI is unavailable and no GITHUB_TOKEN is set, so authentication must come from the local git credential store. Also covers the read-after-write caching trap that makes a successful PATCH look like a silent no-op.

  • 4 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added September 24, 2026
ai-agentsrustshellgitapi

Works with

  • terminal
  • cli
  • api

Security analysis

A100/100

Scanned September 24, 2026

npx -y skills add JZKK720/cubecloud-skills-bundle-kit --skill github-repo-metadata --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Github Repo Metadata?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Github Repo Metadata
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/jzkk720-github-repo-metadata/badge)](https://www.skillsdirectory.com/skills/jzkk720-github-repo-metadata)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: github-repo-metadata
description: >
  Use when updating a GitHub repository's description, homepage, topics, or
  other metadata via the API — especially when the gh CLI is unavailable and no
  GITHUB_TOKEN is set, so authentication must come from the local git credential
  store. Also covers the read-after-write caching trap that makes a successful
  PATCH look like a silent no-op.
license: MIT
metadata:
  author: cubecloud-io
  version: "1.0"
---

# GitHub repo metadata without the `gh` CLI

## The trap this skill exists to prevent

You want to change a repo's description. You check for tooling:

- `Get-Command gh` → **absent**
- `$env:GITHUB_TOKEN` / `$env:GH_TOKEN` → **unset**
- unauthenticated `PATCH /repos/...` → **401**

The obvious conclusion is *"no auth, this is blocked, ask the user for a token."*
**That conclusion is wrong**, and it is the failure this skill diagnoses. A machine
that has ever pushed over HTTPS with `credential.helper=manager` holds a usable
token in the Windows credential store. `git push` works; the API works too — you
just have to ask the credential store instead of the environment.

**Do not report "blocked" until you have tried the credential store.** Check for
an existing credential before asking a human for anything.

## Decision order

| Check | If present | If absent |
|---|---|---|
| `gh auth status` | use `gh` (simplest) | continue |
| `$env:GITHUB_TOKEN` / `GH_TOKEN` | use it | continue |
| git credential store | use it — see below | **now** it is genuinely blocked |

## Read the credential (never print it, never write it)

```powershell
# Suppress interactive prompts FIRST or this can block on a GUI dialog.
$env:GIT_TERMINAL_PROMPT = "0"
$env:GCM_INTERACTIVE     = "never"

$raw = "protocol=https`nhost=github.com`n`n" | git credential fill 2>&1
$tok = ($raw | Where-Object { $_ -like "password=*" } | Select-Object -First 1) -replace "^password=", ""
if (-not $tok) { throw "no stored credential" }
```

Keep `$tok` **in memory only**. Never echo it, never redirect it to a file.

Confirm the credential is usable and learn what it may do:

```powershell
Invoke-WebRequest -Uri "https://api.github.com/user" -Headers @{ Authorization = "Bearer $tok"; "User-Agent" = "ps" }
# 200 -> authenticated. The x-oauth-scopes response header names the scopes.
```

`repo` scope covers repository metadata writes. A response with an **empty**
`x-oauth-scopes` header usually means a *fine-grained* PAT — those omit the scope
header, and write access depends on the per-repo permissions chosen at creation,
so read `permissions` from `GET /repos/{owner}/{repo}` instead of guessing.

## Write the metadata

```powershell
$body  = @{ description = $desc; homepage = $url } | ConvertTo-Json -Compress
$bytes = [Text.Encoding]::UTF8.GetBytes($body)   # encode explicitly; a non-ASCII
                                                 # char in a default body fails
Invoke-WebRequest -Uri "https://api.github.com/repos/$owner/$repo" -Method Patch `
  -Headers @{
    Authorization          = "Bearer $tok"
    "User-Agent"           = "ps"
    Accept                 = "application/vnd.github+json"
    "X-GitHub-Api-Version" = "2022-11-28"
  } `
  -ContentType "application/json; charset=utf-8" `
  -Body $bytes
```

GitHub enforces a **350-character** description limit — check length before sending.

## Verify — and do not trust the immediate read-back

```powershell
$r = Invoke-RestMethod -Uri "https://api.github.com/repos/$owner/$repo?ts=$(Get-Date -UFormat %s)" `
  -Headers @{ "User-Agent" = "ps"; "Cache-Control" = "no-cache" }
```

**`GET /repos/{owner}/{repo}` is cached.** A PATCH returning **200** can still read
back the *old* value seconds later. Do not conclude the write failed. Wait ~30–60s
or add a cache-busting query param, then re-read. Confirm `updated_at` moved.

## Dead ends already ruled out

- `gh` CLI — frequently simply not installed; `gh`-based skills fail entirely here.
- `GITHUB_TOKEN` / `GH_TOKEN` — commonly unset even when pushing works fine.
- unauthenticated PATCH — always 401; never a viable path.
- Existing skills `github-ops` and `attach-review-to-pr` **both assume `gh`**
  (`gh auth status`, `gh auth login`) and so do not help on a `gh`-less machine.

## Safety

- Read the token in memory; never print, log, or persist it.
- Report only non-identifying facts: length and token class
  (`gh?_` / `github_pat_` / 40-hex), plus the login from `GET /user`.
- After the run, sweep the working tree for token-shaped strings and confirm `0`:

```powershell
Get-ChildItem . -Recurse -File | Where-Object { $_.FullName -notmatch "\\\.git\\" } |
  Select-String -Pattern "\bgh[pousr]_[A-Za-z0-9]{36}\b"
```

- If the credential carries `repo` scope it is a **full-write admin credential**.
  That is normal for a dev box, but say so plainly when you use it.

## Passed verification (why this skill is trusted)

Applied to `JZKK720/cubecloud-skills-bundle-kit`: `PATCH` → **200**; after cache
expiry the live read-back showed the new description and homepage, and `updated_at`
had advanced. Negative control: the unauthenticated PATCH returned **401**, so the
success above is attributable to the stored credential and not to public write
access.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.