Skip to main content

GitHub Secrets Manager

github-secrets-manager.py manages local plaintext copies of GitHub Actions repository secrets and shared organization secret values, then syncs them to GitHub by using the authenticated GitHub CLI (gh).

GitHub does not allow reading secret values after they are created. This script solves that by keeping local copies of the values, plus local creation and update timestamps, so repository secrets can be recreated or updated from your machine. For organizations, one local shared secret can be applied to every repository that already has a remote secret with the same name.

Requirements

  • Python 3
  • GitHub CLI (gh)
  • An authenticated GitHub CLI session:
gh auth login

The script manages GitHub Actions repository secrets. It does not manage environment, organization-level, Dependabot, Codespaces, or Agents secrets.

Local Storage

By default, local secrets are stored under:

~/.github-local-secrets

You can change that location with --secrets-dir:

./github-secrets-manager.py --secrets-dir ~/secure/github-secrets local list octocat/hello-world

Repository-specific local secrets are stored using this layout:

SECRETS_DIR/
  OWNER/
    REPO/
      metadata.json
      secrets/
        SECRET_NAME.secret

Organization shared local secrets are stored using this layout:

SECRETS_DIR/
  organizations/
    ORG/
      metadata.json
      secrets/
        SECRET_NAME.secret

Each local secret value is stored as a plaintext UTF-8 file. Secret files are written with 0600 permissions. Protect the configured secrets directory as sensitive material and do not commit it to Git.

metadata.json stores local metadata for each secret:

  • created_at
  • updated_at
  • relative local file path

Usage

./github-secrets-manager.py [--secrets-dir DIR] {local,repo,org} ...

Use --help at any level to see the available commands:

./github-secrets-manager.py --help
./github-secrets-manager.py local --help
./github-secrets-manager.py repo --help
./github-secrets-manager.py org --help
./github-secrets-manager.py org local --help

Local Commands

Create a local secret from standard input:

printf 'my-secret-value\n' | ./github-secrets-manager.py local create octocat/hello-world API_KEY --stdin

Create a local multiline secret:

./github-secrets-manager.py local create octocat/hello-world PRIVATE_KEY --stdin <<'EOF'
-----BEGIN PRIVATE KEY-----
line 1
line 2
-----END PRIVATE KEY-----
EOF

Create a local secret from a file:

./github-secrets-manager.py local create octocat/hello-world NPM_TOKEN --value-file ./npm-token.txt

Update or create a local secret:

printf 'new-value\n' | ./github-secrets-manager.py local update octocat/hello-world API_KEY --stdin

List local secrets and their metadata:

./github-secrets-manager.py local list octocat/hello-world

Show a local secret value:

./github-secrets-manager.py local show octocat/hello-world API_KEY

Delete a local secret:

./github-secrets-manager.py local delete octocat/hello-world API_KEY

Repository Commands

List GitHub Actions secrets configured in a repository:

./github-secrets-manager.py repo list octocat/hello-world

GitHub only returns secret names and update metadata. It never returns secret values.

Create or update one GitHub secret from its local value:

./github-secrets-manager.py repo create octocat/hello-world API_KEY

Preview that operation without writing to GitHub:

./github-secrets-manager.py repo create octocat/hello-world API_KEY --dry-run

Update selected GitHub secrets from local values:

./github-secrets-manager.py repo update octocat/hello-world --secrets API_KEY,NPM_TOKEN

Update all remote secrets that have matching local values:

./github-secrets-manager.py repo update octocat/hello-world --all

Preview repository updates without writing to GitHub:

./github-secrets-manager.py repo update octocat/hello-world --all --dry-run

Compare local and remote secrets:

./github-secrets-manager.py repo sync octocat/hello-world

The sync report uses these statuses:

  • remote-and-local: the secret exists in GitHub and locally.
  • missing-local: the secret exists in GitHub but no local value is available.
  • local-only: the secret exists locally but not in GitHub.

Remote secrets that are missing locally are reported only. They are not deleted or overwritten.

Organization Commands

Organization local secrets are stored once per organization and can be synced to repositories in that organization. The sync still writes repository-level GitHub Actions secrets; it does not create GitHub organization-level secrets.

Create an organization local secret from standard input:

printf 'shared-token-value\n' | ./github-secrets-manager.py org local create my-organization API_TOKEN --stdin

Create an organization local multiline secret:

./github-secrets-manager.py org local create my-organization PRIVATE_KEY --stdin <<'EOF'
-----BEGIN PRIVATE KEY-----
line 1
line 2
-----END PRIVATE KEY-----
EOF

Create an organization local secret from a file:

./github-secrets-manager.py org local create my-organization NPM_TOKEN --value-file ./npm-token.txt

Update or create an organization local secret:

printf 'new-shared-value\n' | ./github-secrets-manager.py org local update my-organization API_TOKEN --stdin

List organization local secrets:

./github-secrets-manager.py org local list my-organization

Show an organization local secret value:

./github-secrets-manager.py org local show my-organization API_TOKEN

Delete an organization local secret:

./github-secrets-manager.py org local delete my-organization API_TOKEN

Update matching repository secrets across an organization:

./github-secrets-manager.py org sync my-organization

The command lists repositories in the organization and updates only remote repository secrets that have matching organization local values. If a repository does not already have a remote secret with the same name, the script skips it.

Sync only selected organization local secrets:

./github-secrets-manager.py org sync my-organization --secrets API_TOKEN,NPM_TOKEN

Preview organization-wide updates without writing to GitHub:

./github-secrets-manager.py org sync my-organization --dry-run

Include archived repositories:

./github-secrets-manager.py org sync my-organization --include-archived

Use a custom local secrets directory for an organization sync:

./github-secrets-manager.py \
  --secrets-dir ~/secure/github-secrets \
  org sync my-organization \
  --dry-run

Example Workflow

Create shared local secrets for an organization:

printf 'token-value\n' | ./github-secrets-manager.py org local create my-org API_TOKEN --stdin
./github-secrets-manager.py org local create my-org PRIVATE_KEY --value-file ./private-key.pem

Review what is stored locally:

./github-secrets-manager.py org local list my-org

Preview the organization-wide GitHub update:

./github-secrets-manager.py org sync my-org --dry-run

Apply the shared values to matching repository secrets:

./github-secrets-manager.py org sync my-org

Apply only one shared value:

./github-secrets-manager.py org sync my-org --secrets API_TOKEN

Use repository-local commands for repository-specific exceptions that should not come from the shared organization store.

Safety Notes

  • Local secret values are plaintext. Keep the secrets directory private.
  • Do not store the secrets directory inside a Git repository.
  • Secret values are sent to gh secret set through standard input, not through command-line arguments.
  • Use --dry-run before repository or organization updates when you want to inspect what would change.
  • The script validates repository names as OWNER/REPO and secret names as uppercase/underscore-compatible identifiers, though lowercase letters are also accepted.

Metadata

Release files for github-secrets-manager 0.0.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for github-secrets-manager 0.0.1
File Size Uploaded
github_secrets_manager-0.0.1.tar.gz 10.2 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for github-secrets-manager 0.0.1
File Interpreter ABI Platform
github_secrets_manager-0.0.1-py3-none-any.whl Python 3 none any Details

Total release size: 19.3 kB

Release files / github_secrets_manager-0.0.1.tar.gz

Download URL github_secrets_manager-0.0.1.tar.gz
Size 10.2 kB
Tags Source
SHA-256 checksum
How to use checksums
8f635df6920a3a231e9529ddd62df31ee6e10e1443375b1ffb39b822b512e4d3
BLAKE2b-256 checksum
How to use checksums
6053ef95334316ff75092f71c84c95830deaf4489522077114e9023548614405
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.4

Release files / github_secrets_manager-0.0.1-py3-none-any.whl

Download URL github_secrets_manager-0.0.1-py3-none-any.whl
Size 9.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
d5a9753d8f8de93d9ac2518394b51247b77326bb83f0e66901d7a94b050e2ee8
BLAKE2b-256 checksum
How to use checksums
0e3ebe9f8713891e795b6fd00c196c00c744f10026f45583fcf08d3a5db3d4fe
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.4

Release history Release notifications | RSS feed

This release

0.0.1 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page