From 4911fa404558a6fa9243566b77f915113b32d337 Mon Sep 17 00:00:00 2001 From: hatayama Date: Sun, 26 Jul 2026 02:34:37 +0900 Subject: [PATCH] chore: Set persist-credentials false on pull-request workflows actions/checkout stores GITHUB_TOKEN in the local Git config by default, so any repository script or test a pull-request workflow runs from the PR branch can read it. dead-code.yml already disabled credential persistence; the remaining pull-request workflows that execute repository code did not. - Set persist-credentials: false on every actions/checkout step in build-and-test, code-complexity, security-scan, pr-title, and unity-compile-check-and-test-runner. None of them use Git authentication after checkout, so nothing depends on the persisted token. - Add TestPullRequestWorkflowsDisableCredentialPersistence so a future pull-request workflow cannot reintroduce the leak. - Document the rule in docs/github-actions-security.md. Closes #1998 --- .github/workflows/build-and-test.yml | 5 ++++ .github/workflows/code-complexity.yml | 2 ++ .github/workflows/pr-title.yml | 2 ++ .github/workflows/security-scan.yml | 4 +++ .../unity-compile-check-and-test-runner.yml | 1 + .../github_actions_security_test.go | 26 +++++++++++++++++++ docs/github-actions-security.md | 7 +++++ 7 files changed, 47 insertions(+) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 49a658bf0..13119feec 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -22,6 +22,7 @@ jobs: - name: Checkout repository uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd with: + persist-credentials: false fetch-depth: 0 - name: Setup Go @@ -111,6 +112,8 @@ jobs: steps: - name: Checkout repository uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + with: + persist-credentials: false - name: Setup Go uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c @@ -163,6 +166,8 @@ jobs: steps: - name: Checkout repository uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + with: + persist-credentials: false - name: Validate Unity Package structure run: | diff --git a/.github/workflows/code-complexity.yml b/.github/workflows/code-complexity.yml index 538678d40..3c12dd331 100644 --- a/.github/workflows/code-complexity.yml +++ b/.github/workflows/code-complexity.yml @@ -25,6 +25,8 @@ jobs: steps: - name: Checkout repository uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + with: + persist-credentials: false - name: Setup Go uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c diff --git a/.github/workflows/pr-title.yml b/.github/workflows/pr-title.yml index f0a7737ac..d1e84d26c 100644 --- a/.github/workflows/pr-title.yml +++ b/.github/workflows/pr-title.yml @@ -15,6 +15,8 @@ jobs: steps: - name: Checkout repository uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + with: + persist-credentials: false - name: Setup Go uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c diff --git a/.github/workflows/security-scan.yml b/.github/workflows/security-scan.yml index 9096eff9f..c65cd1242 100644 --- a/.github/workflows/security-scan.yml +++ b/.github/workflows/security-scan.yml @@ -47,6 +47,8 @@ jobs: steps: - name: Checkout code uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + with: + persist-credentials: false - name: Setup Go uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c @@ -98,6 +100,8 @@ jobs: steps: - name: Checkout code uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + with: + persist-credentials: false - name: Setup Go uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c diff --git a/.github/workflows/unity-compile-check-and-test-runner.yml b/.github/workflows/unity-compile-check-and-test-runner.yml index 976c8dff6..206358c73 100644 --- a/.github/workflows/unity-compile-check-and-test-runner.yml +++ b/.github/workflows/unity-compile-check-and-test-runner.yml @@ -39,6 +39,7 @@ jobs: - name: Checkout repository uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd with: + persist-credentials: false # Full history is required so the change-detection step can diff the # PR head against its base. fetch-depth: 0 diff --git a/cli/release-automation/internal/architecture/github_actions_security_test.go b/cli/release-automation/internal/architecture/github_actions_security_test.go index 803761fb6..c8ac0e050 100644 --- a/cli/release-automation/internal/architecture/github_actions_security_test.go +++ b/cli/release-automation/internal/architecture/github_actions_security_test.go @@ -61,6 +61,32 @@ func TestPullRequestWorkflowsDisableSetupGoCache(t *testing.T) { } } +// Tests that checkout does not persist GITHUB_TOKEN in pull request workflows. +func TestPullRequestWorkflowsDisableCredentialPersistence(t *testing.T) { + repositoryRoot := findRepositoryRoot(t) + violations := []string{} + for _, workflowPath := range workflowFilePaths(t, repositoryRoot) { + lines := readWorkflowLines(t, workflowPath) + if !workflowRunsOnPullRequest(lines) { + continue + } + for lineIndex, line := range lines { + actionRef, ok := parseUsesAction(line) + if !ok || actionRepository(actionRef) != "actions/checkout" { + continue + } + if stepContains(lines, lineIndex, "persist-credentials: false") { + continue + } + violations = append(violations, workflowViolation(repositoryRoot, workflowPath, lineIndex, actionRef, "set persist-credentials: false for checkout in pull request workflows")) + } + } + if len(violations) > 0 { + sort.Strings(violations) + t.Fatalf("pull request checkout credential persistence policy violations:\n%s", strings.Join(violations, "\n")) + } +} + // Tests that pull request workflow cache actions are guarded behind trusted Unity secrets. func TestPullRequestWorkflowCacheActionsRequireTrustedUnitySecrets(t *testing.T) { repositoryRoot := findRepositoryRoot(t) diff --git a/docs/github-actions-security.md b/docs/github-actions-security.md index a73d18d3b..f591fdfff 100644 --- a/docs/github-actions-security.md +++ b/docs/github-actions-security.md @@ -19,3 +19,10 @@ Use `cache: false` for `actions/setup-go` in workflows triggered by Unity `actions/cache` steps in pull request workflows must stay behind the Unity license secret guard so forked pull requests cannot use those cache entries. + +`actions/checkout` steps in workflows triggered by `pull_request` or +`pull_request_target` must set `persist-credentials: false`. By default checkout +writes `GITHUB_TOKEN` into the local Git config, so any repository script or test +that the workflow runs from the pull request branch can read it. Release +workflows that genuinely push back to the repository are the only place where +credential persistence is appropriate.