Skip to content

feat: sync secrets workflow for sibling repositories#825

Open
frostebite wants to merge 1 commit intomainfrom
feat/sync-secrets-to-orchestrator
Open

feat: sync secrets workflow for sibling repositories#825
frostebite wants to merge 1 commit intomainfrom
feat/sync-secrets-to-orchestrator

Conversation

@frostebite
Copy link
Copy Markdown
Member

@frostebite frostebite commented Mar 29, 2026

Summary

  • Adds a manually-triggered workflow (sync-secrets.yml) that copies secrets from unity-builder to sibling repos (orchestrator, cli)
  • Uses GIT_PRIVATE_TOKEN for cross-repo GitHub API access via gh secret set
  • Supports dry-run mode to preview what would be synced without writing
  • Skips secrets not available in this repo's context (repo + org level)

Secrets synced

Secret Used by
UNITY_EMAIL Orchestrator integration tests
UNITY_PASSWORD Orchestrator integration tests
UNITY_SERIAL Orchestrator integration tests
GIT_PRIVATE_TOKEN Orchestrator CI (git operations)
LOCALSTACK_AUTH_TOKEN Orchestrator LocalStack integration tests
GOOGLE_SERVICE_ACCOUNT_EMAIL GCP provider tests
GOOGLE_SERVICE_ACCOUNT_KEY GCP provider tests
CODECOV_TOKEN Code coverage reporting

Usage

  1. Go to Actions → "Sync Secrets to Repositories"
  2. Select target repo (orchestrator or cli)
  3. Optionally enable dry run
  4. Click "Run workflow"

Context

The orchestrator repo has zero secrets configured, causing all LocalStack-based integration tests to fail. This workflow provides a convenient way to keep secrets in sync across game-ci repos without manual copying.

Note: LOCALSTACK_AUTH_TOKEN must first be added to unity-builder (or as an org secret) before it can be synced. LocalStack v4+ requires this token.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Chores
    • Added a new manual workflow for syncing secrets across repositories, including a dry-run mode for previewing changes before applying them.

Adds a manually-triggered workflow that copies secrets from
unity-builder (repo + org level) to target repos like orchestrator
and cli. Uses GIT_PRIVATE_TOKEN for cross-repo API access.

Secrets synced: UNITY_EMAIL, UNITY_PASSWORD, UNITY_SERIAL,
GIT_PRIVATE_TOKEN, LOCALSTACK_AUTH_TOKEN, GOOGLE_SERVICE_ACCOUNT_EMAIL,
GOOGLE_SERVICE_ACCOUNT_KEY, CODECOV_TOKEN.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 29, 2026

📝 Walkthrough

Walkthrough

A new GitHub Actions workflow has been added that enables manual synchronization of secrets to target repositories. The workflow accepts configuration inputs for the target repository and a dry-run mode, then processes a predefined list of environment variables, syncing each as a GitHub secret or logging skipped entries.

Changes

Cohort / File(s) Summary
GitHub Actions Workflow
.github/workflows/sync-secrets.yml
New workflow for syncing secrets to target repositories via workflow_dispatch trigger. Accepts target_repo (choice: game-ci/orchestrator, game-ci/cli) and dry_run (boolean) inputs. Maps and syncs eight secrets (UNITY\_EMAIL, UNITY\_PASSWORD, UNITY\_SERIAL, GIT\_PRIVATE\_TOKEN, LOCALSTACK\_AUTH\_TOKEN, GOOGLE\_SERVICE\_ACCOUNT\_EMAIL, GOOGLE\_SERVICE\_ACCOUNT\_KEY, CODECOV\_TOKEN) from environment variables to target repository using GitHub CLI.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Suggested reviewers

  • GabLeRoux
  • webbertakken

Poem

🐰 A workflow hops along with care,
Secrets bundled, secrets shared,
Dry-run first, then swift and true,
Twenty repositories, all brand new! ✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main change: a new GitHub Actions workflow that synchronizes secrets to sibling repositories.
Description check ✅ Passed The description comprehensively covers the changes with a summary, detailed secrets table, usage instructions, and relevant context; all key template sections are addressed.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/sync-secrets-to-orchestrator

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link
Copy Markdown

Cat Gif

Comment on lines +22 to +81
name: Sync secrets to ${{ inputs.target_repo }}
runs-on: ubuntu-latest
steps:
- name: Sync secrets
env:
GH_TOKEN: ${{ secrets.GIT_PRIVATE_TOKEN }}
TARGET_REPO: ${{ inputs.target_repo }}
DRY_RUN: ${{ inputs.dry_run }}
# Secrets to sync — values come from repo + org secrets available here
SECRET_UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
SECRET_UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
SECRET_UNITY_SERIAL: ${{ secrets.UNITY_SERIAL }}
SECRET_GIT_PRIVATE_TOKEN: ${{ secrets.GIT_PRIVATE_TOKEN }}
SECRET_LOCALSTACK_AUTH_TOKEN: ${{ secrets.LOCALSTACK_AUTH_TOKEN }}
SECRET_GOOGLE_SERVICE_ACCOUNT_EMAIL: ${{ secrets.GOOGLE_SERVICE_ACCOUNT_EMAIL }}
SECRET_GOOGLE_SERVICE_ACCOUNT_KEY: ${{ secrets.GOOGLE_SERVICE_ACCOUNT_KEY }}
SECRET_CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
run: |
SECRETS=(
"UNITY_EMAIL:SECRET_UNITY_EMAIL"
"UNITY_PASSWORD:SECRET_UNITY_PASSWORD"
"UNITY_SERIAL:SECRET_UNITY_SERIAL"
"GIT_PRIVATE_TOKEN:SECRET_GIT_PRIVATE_TOKEN"
"LOCALSTACK_AUTH_TOKEN:SECRET_LOCALSTACK_AUTH_TOKEN"
"GOOGLE_SERVICE_ACCOUNT_EMAIL:SECRET_GOOGLE_SERVICE_ACCOUNT_EMAIL"
"GOOGLE_SERVICE_ACCOUNT_KEY:SECRET_GOOGLE_SERVICE_ACCOUNT_KEY"
"CODECOV_TOKEN:SECRET_CODECOV_TOKEN"
)

synced=0
skipped=0

for entry in "${SECRETS[@]}"; do
name="${entry%%:*}"
env_var="${entry##*:}"
value="${!env_var}"

if [ -z "$value" ]; then
echo "⏭ SKIP: $name (not available in this repo's context)"
skipped=$((skipped + 1))
continue
fi

if [ "$DRY_RUN" = "true" ]; then
echo "🔍 DRY RUN: would sync $name → $TARGET_REPO"
else
echo "$value" | gh secret set "$name" -R "$TARGET_REPO" --body -
echo "✅ SYNCED: $name → $TARGET_REPO"
fi
synced=$((synced + 1))
done

echo ""
echo "=== Summary ==="
echo "Synced: $synced"
echo "Skipped (not available): $skipped"
echo "Target: $TARGET_REPO"
if [ "$DRY_RUN" = "true" ]; then
echo "Mode: DRY RUN (no secrets were written)"
fi

Check warning

Code scanning / CodeQL

Workflow does not contain permissions Medium

Actions job or workflow does not limit the permissions of the GITHUB_TOKEN. Consider setting an explicit permissions block, using the following as a minimal starting point: {}

Copilot Autofix

AI 5 days ago

In general, the fix is to add an explicit permissions block that limits the GITHUB_TOKEN to the least privileges required. This should be added either at the top level of the workflow (to apply to all jobs) or at the job level (for sync-secrets). Since this workflow only has a single job and uses a separate secret (GIT_PRIVATE_TOKEN) for writing secrets, GITHUB_TOKEN does not appear to need any write permissions. The safest minimal configuration is permissions: contents: read at the job or workflow level.

The single best way to fix this without affecting existing behavior is to add a permissions block under the sync-secrets job, right after runs-on: ubuntu-latest. Given the script only calls gh secret set using GH_TOKEN from a custom secret and does not interact with repository contents, issues, or pull requests via GITHUB_TOKEN, we can set permissions: contents: read. This keeps GITHUB_TOKEN usable for basic checkout or read-only operations if added later, while preventing unintended write access.

Concretely, in .github/workflows/sync-secrets.yml, modify the sync-secrets job so that:

  sync-secrets:
    name: Sync secrets to ${{ inputs.target_repo }}
    runs-on: ubuntu-latest
    permissions:
      contents: read
    steps:
      - name: Sync secrets
      ...

No new imports or libraries are needed, as this is purely a YAML configuration change.

Suggested changeset 1
.github/workflows/sync-secrets.yml

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/.github/workflows/sync-secrets.yml b/.github/workflows/sync-secrets.yml
--- a/.github/workflows/sync-secrets.yml
+++ b/.github/workflows/sync-secrets.yml
@@ -21,6 +21,8 @@
   sync-secrets:
     name: Sync secrets to ${{ inputs.target_repo }}
     runs-on: ubuntu-latest
+    permissions:
+      contents: read
     steps:
       - name: Sync secrets
         env:
EOF
@@ -21,6 +21,8 @@
sync-secrets:
name: Sync secrets to ${{ inputs.target_repo }}
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Sync secrets
env:
Copilot is powered by AI and may make mistakes. Always verify output.
@codecov
Copy link
Copy Markdown

codecov bot commented Mar 29, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 31.23%. Comparing base (4a7fc08) to head (f0b74c7).

Additional details and impacted files

Impacted file tree graph

@@           Coverage Diff           @@
##             main     #825   +/-   ##
=======================================
  Coverage   31.23%   31.23%           
=======================================
  Files          84       84           
  Lines        4565     4565           
  Branches     1054     1054           
=======================================
  Hits         1426     1426           
  Misses       3139     3139           
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
.github/workflows/sync-secrets.yml (1)

27-29: Add auth preflight for clearer non-dry-run failures.

Right now, auth/scope problems only surface during gh secret set execution. A small preflight makes failures immediate and clearer for operators.

Suggested patch
       - name: Sync secrets
+        shell: bash
         env:
           GH_TOKEN: ${{ secrets.GIT_PRIVATE_TOKEN }}
           TARGET_REPO: ${{ inputs.target_repo }}
           DRY_RUN: ${{ inputs.dry_run }}
@@
         run: |
+          if [ "$DRY_RUN" != "true" ]; then
+            if [ -z "${GH_TOKEN:-}" ]; then
+              echo "::error::GIT_PRIVATE_TOKEN is required for non-dry-run sync."
+              exit 1
+            fi
+            gh auth status >/dev/null 2>&1 || {
+              echo "::error::gh authentication failed (missing/invalid token or scopes)."
+              exit 1
+            }
+          fi
+
           SECRETS=(

Also applies to: 39-69

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/sync-secrets.yml around lines 27 - 29, Add an auth
preflight step that runs only when DRY_RUN is false to fail early on token/scope
problems: use the existing GH_TOKEN and conditionally execute a lightweight
check (for example running `gh auth status` or `gh api /user`) in a step named
like "auth-preflight" or with id "auth_preflight" before any `gh secret set`
calls so operators get immediate, clear failures instead of errors surfacing
later during secret operations.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.github/workflows/sync-secrets.yml:
- Around line 20-24: Add an explicit permissions block at the workflow root to
restrict the default GITHUB_TOKEN (follow least privilege). Insert a top-level
permissions section (above jobs) such as "permissions: contents: read" or
"permissions: none" depending on whether the workflow needs repo contents; this
will limit GITHUB_TOKEN access for the "sync-secrets" job while you continue to
use the explicit GH_TOKEN for gh secret set.
- Around line 31-38: The sync secrets allowlist is missing UNITY_LICENSE which
is used by downstream workflows (e.g., build-tests-windows.yml); update the
secret mappings in .github/workflows/sync-secrets.yml by adding a mapping for
UNITY_LICENSE (e.g., SECRET_UNITY_LICENSE -> ${{ secrets.UNITY_LICENSE }})
alongside the existing SECRET_UNITY_* entries so the workflow can sync that
secret for downstream use.

---

Nitpick comments:
In @.github/workflows/sync-secrets.yml:
- Around line 27-29: Add an auth preflight step that runs only when DRY_RUN is
false to fail early on token/scope problems: use the existing GH_TOKEN and
conditionally execute a lightweight check (for example running `gh auth status`
or `gh api /user`) in a step named like "auth-preflight" or with id
"auth_preflight" before any `gh secret set` calls so operators get immediate,
clear failures instead of errors surfacing later during secret operations.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: c1a893b8-5835-481a-b1bd-bf59fd200cdd

📥 Commits

Reviewing files that changed from the base of the PR and between 4a7fc08 and f0b74c7.

📒 Files selected for processing (1)
  • .github/workflows/sync-secrets.yml

Comment on lines +20 to +24
jobs:
sync-secrets:
name: Sync secrets to ${{ inputs.target_repo }}
runs-on: ubuntu-latest
steps:
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

cat -n .github/workflows/sync-secrets.yml

Repository: game-ci/unity-builder

Length of output: 3535


🏁 Script executed:

find .github/workflows -name "*.yml" -o -name "*.yaml" | head -5 | xargs grep -l "permissions:" 2>/dev/null

Repository: game-ci/unity-builder

Length of output: 49


🏁 Script executed:

find .github/workflows -name "*.yml" -o -name "*.yaml" | xargs head -30 | grep -A 5 "^jobs:" | head -20

Repository: game-ci/unity-builder

Length of output: 547


🏁 Script executed:

find .github/workflows -type f \( -name "*.yml" -o -name "*.yaml" \) | wc -l

Repository: game-ci/unity-builder

Length of output: 67


🏁 Script executed:

find .github/workflows -type f \( -name "*.yml" -o -name "*.yaml" \) -exec grep -l "^permissions:" {} \;

Repository: game-ci/unity-builder

Length of output: 195


🏁 Script executed:

grep -A 2 "^permissions:" .github/workflows/integrity-check.yml .github/workflows/orchestrator-async-checks.yml .github/workflows/orchestrator-integrity.yml

Repository: game-ci/unity-builder

Length of output: 585


🏁 Script executed:

# Verify the syntax of permissions: {} in GitHub Actions documentation context
# Check if there are any other cross-repo secret workflows to compare
grep -r "gh secret set" .github/workflows/

Repository: game-ci/unity-builder

Length of output: 178


Add explicit workflow permissions (least privilege).

The workflow lacks an explicit permissions block, leaving default GITHUB_TOKEN permissions implicit. While this workflow uses an explicit GH_TOKEN for gh secret set, the default token should still be restricted to follow least-privilege principle and align with the repository's existing security pattern (other workflows declare explicit permissions).

Suggested patch
 name: Sync Secrets to Repositories
 
 on:
   workflow_dispatch:
+    inputs:
       type: boolean
+
+permissions: {}
 
 jobs:
   sync-secrets:
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/sync-secrets.yml around lines 20 - 24, Add an explicit
permissions block at the workflow root to restrict the default GITHUB_TOKEN
(follow least privilege). Insert a top-level permissions section (above jobs)
such as "permissions: contents: read" or "permissions: none" depending on
whether the workflow needs repo contents; this will limit GITHUB_TOKEN access
for the "sync-secrets" job while you continue to use the explicit GH_TOKEN for
gh secret set.

Comment on lines +31 to +38
SECRET_UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
SECRET_UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
SECRET_UNITY_SERIAL: ${{ secrets.UNITY_SERIAL }}
SECRET_GIT_PRIVATE_TOKEN: ${{ secrets.GIT_PRIVATE_TOKEN }}
SECRET_LOCALSTACK_AUTH_TOKEN: ${{ secrets.LOCALSTACK_AUTH_TOKEN }}
SECRET_GOOGLE_SERVICE_ACCOUNT_EMAIL: ${{ secrets.GOOGLE_SERVICE_ACCOUNT_EMAIL }}
SECRET_GOOGLE_SERVICE_ACCOUNT_KEY: ${{ secrets.GOOGLE_SERVICE_ACCOUNT_KEY }}
SECRET_CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

cd /tmp && git ls-files | grep -E "\.github/workflows/" | head -20

Repository: game-ci/unity-builder

Length of output: 133


🏁 Script executed:

cat -n .github/workflows/sync-secrets.yml | head -60

Repository: game-ci/unity-builder

Length of output: 2698


🏁 Script executed:

cat -n .github/workflows/build-tests-windows.yml | grep -i "unity_license" -A 2 -B 2

Repository: game-ci/unity-builder

Length of output: 826


🏁 Script executed:

cat .github/workflows/orchestrator-integrity.yml | grep -E "AWS_ACCESS_KEY_ID|AWS_SECRET_ACCESS_KEY" -A 2 -B 2

Repository: game-ci/unity-builder

Length of output: 4497


🏁 Script executed:

cat .github/workflows/orchestrator-integrity.yml | grep -E "secrets\." -i | head -20

Repository: game-ci/unity-builder

Length of output: 1172


🏁 Script executed:

rg "secrets\.AWS_" .github/workflows/ -A 1 -B 1

Repository: game-ci/unity-builder

Length of output: 436


🏁 Script executed:

cat .github/workflows/orchestrator-async-checks.yml | grep -A 10 -B 10 "AWS_ACCESS_KEY_ID.*secrets"

Repository: game-ci/unity-builder

Length of output: 830


🏁 Script executed:

cat -n .github/workflows/sync-secrets.yml | tail -30

Repository: game-ci/unity-builder

Length of output: 1239


Add UNITY_LICENSE to the secrets allowlist for sync.

The mapping omits UNITY_LICENSE, which is actively referenced in .github/workflows/build-tests-windows.yml (lines 109, 136, 161). This secret is necessary for downstream workflows and should be included in the sync.

Note: AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY are not referenced as actual secrets in the workflows—they are hardcoded test values (in orchestrator-integrity.yml) or commented out (in orchestrator-async-checks.yml), so they should not be added to the sync allowlist.

Suggested patch
          SECRET_UNITY_SERIAL: ${{ secrets.UNITY_SERIAL }}
+         SECRET_UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
          SECRET_GIT_PRIVATE_TOKEN: ${{ secrets.GIT_PRIVATE_TOKEN }}
            "UNITY_SERIAL:SECRET_UNITY_SERIAL"
+           "UNITY_LICENSE:SECRET_UNITY_LICENSE"
            "GIT_PRIVATE_TOKEN:SECRET_GIT_PRIVATE_TOKEN"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/sync-secrets.yml around lines 31 - 38, The sync secrets
allowlist is missing UNITY_LICENSE which is used by downstream workflows (e.g.,
build-tests-windows.yml); update the secret mappings in
.github/workflows/sync-secrets.yml by adding a mapping for UNITY_LICENSE (e.g.,
SECRET_UNITY_LICENSE -> ${{ secrets.UNITY_LICENSE }}) alongside the existing
SECRET_UNITY_* entries so the workflow can sync that secret for downstream use.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants