Skip to content

fix(agreements): mint GitHub App installation token in-job#73

Merged
mbruzda-splunk merged 2 commits into
mainfrom
fix/agreements-mint-app-token-in-job
Jun 9, 2026
Merged

fix(agreements): mint GitHub App installation token in-job#73
mbruzda-splunk merged 2 commits into
mainfrom
fix/agreements-mint-app-token-in-job

Conversation

@mbruzda-splunk

@mbruzda-splunk mbruzda-splunk commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

Problem

Add-on repos rolled out from splunk/addonfactory-repository-template now fail the CLA/COC check on every PR, e.g.:

with:

##[error]Please add a personal access token as an environment variable for writing signatures in a remote repository/organization as mentioned in the README.md file
##[error]Could not retrieve repository contents. Status: unknown

Root cause

The template's caller workflow mints a GitHub App installation token in a separate generate-token job and passes it via job outputs to call-workflow-agreements:

jobs:
  generate-token:
    outputs:
      token: ${{ steps.app-token.outputs.token }}
    steps:
      - uses: actions/create-github-app-token@v3
        ...
  call-workflow-agreements:
    needs: generate-token
    uses: splunk/addonfactory-github-workflows/.github/workflows/reusable-agreements.yaml@v1.4
    secrets:
      PERSONAL_ACCESS_TOKEN: ${{ needs.generate-token.outputs.token }}

GitHub Actions auto-classifies the App installation token as a secret and strips it from job outputs with the annotation:

Skip output 'token' since it may contain secret.

So needs.generate-token.outputs.token resolves to an empty string, PERSONAL_ACCESS_TOKEN is empty in the consuming job, and contributor-assistant/github-action rejects the call. This calling pattern cannot be made to work — the App token must be minted in the same job that consumes it.

Change

reusable-agreements.yaml now mints the App token inside each job when App credentials are supplied:

  • Adds two optional secrets: GH_APP_CLIENT_ID and GH_APP_PRIVATE_KEY.
  • If both are set, an installation token scoped to splunk/cla-agreement is generated via actions/create-github-app-token@v3 immediately before invoking contributor-assistant/github-action@v2.6.1.
  • Falls back to legacy PERSONAL_ACCESS_TOKEN when App credentials are not provided (back-compat with existing callers).
  • GH_TOKEN is now optional and defaults to github.token.

Callers using App-token auth can simplify to:

jobs:
  call-workflow-agreements:
    uses: splunk/addonfactory-github-workflows/.github/workflows/reusable-agreements.yaml@vX.Y
    permissions:
      actions: read
      contents: read
      pull-requests: write
      statuses: read
    secrets:
      GH_APP_CLIENT_ID:   ${{ secrets.GH_APP_CLIENT_ID }}
      GH_APP_PRIVATE_KEY: ${{ secrets.GH_APP_PRIVATE_KEY }}

No generate-token job, no PAT.

Backwards compatibility

Fully backwards compatible:

Caller passes Behavior
PERSONAL_ACCESS_TOKEN (legacy) Used directly, as before.
GH_APP_CLIENT_ID + GH_APP_PRIVATE_KEY Token minted in-job and used.
Both App token wins (preferred).
Neither Action will fail with original error (no-op for repos without remote signatures setup).

GH_TOKEN is now optional; existing callers passing it continue to work.

Test plan

End-to-end test via downstream PR — patches splunk-add-on-for-crowdstrike-fdr PR #971 to call this branch's reusable-agreements.yaml with the App secrets. Will link the green run here before merge.

Made with Cursor

The previous calling pattern (see splunk/addonfactory-repository-template
enforce/.github/workflows/agreements.yaml) mints a GitHub App installation
token in a separate `generate-token` job and tries to pass it to
`call-workflow-agreements` via `jobs.<id>.outputs.token`. GitHub Actions
strips secret-classified values from job outputs ("Skip output 'token'
since it may contain secret"), so the downstream job receives an empty
PERSONAL_ACCESS_TOKEN and the contributor-assistant action fails with:

  Please add a personal access token as an environment variable for
  writing signatures in a remote repository/organization ...
  Could not retrieve repository contents. Status: unknown

Example failing run:
https://github.com/splunk/splunk-add-on-for-crowdstrike-fdr/actions/runs/27142130630

This change moves the token mint into the same job that consumes it:
- Adds optional GH_APP_CLIENT_ID / GH_APP_PRIVATE_KEY secrets.
- Generates an installation token scoped to splunk/cla-agreement before
  invoking contributor-assistant/github-action.
- Falls back to the legacy PERSONAL_ACCESS_TOKEN secret when App
  credentials are not supplied, keeping existing callers working.
- GH_TOKEN is now optional and defaults to github.token.

Callers can simplify to:

  jobs:
    call-workflow-agreements:
      uses: splunk/addonfactory-github-workflows/.github/workflows/reusable-agreements.yaml@vX.Y
      secrets:
        GH_APP_CLIENT_ID:   ${{ secrets.GH_APP_CLIENT_ID }}
        GH_APP_PRIVATE_KEY: ${{ secrets.GH_APP_PRIVATE_KEY }}

Co-authored-by: Cursor <cursoragent@cursor.com>
@mbruzda-splunk mbruzda-splunk requested a review from a team as a code owner June 8, 2026 22:34
GitHub Actions does not allow the `secrets` context inside step-level
`if:` expressions (only github, needs, vars, env, inputs are allowed),
which caused the reusable workflow to fail validation in the caller
with a 0-second workflow file error.

Move the App-creds presence check to job-level `env.HAS_APP_CREDS`
(secrets context IS allowed in job env), then condition the
create-github-app-token step on `env.HAS_APP_CREDS == 'true'`.

Co-authored-by: Cursor <cursoragent@cursor.com>
@mbruzda-splunk mbruzda-splunk force-pushed the fix/agreements-mint-app-token-in-job branch from cc43ad4 to 277e0e0 Compare June 8, 2026 22:40
@mbruzda-splunk

Copy link
Copy Markdown
Contributor Author

End-to-end test: GREEN

Tested against splunk/splunk-add-on-for-crowdstrike-fdr PR #973.

A throwaway workflow on that PR calls reusable-agreements.yaml@fix/agreements-mint-app-token-in-job with only:

secrets:
  GH_APP_CLIENT_ID:   ${{ secrets.GH_APP_CLIENT_ID }}
  GH_APP_PRIVATE_KEY: ${{ secrets.GH_APP_PRIVATE_KEY }}

Result: https://github.com/splunk/splunk-add-on-for-crowdstrike-fdr/actions/runs/27171499098

Job Generate App token CLA / COC Assistant Overall
ContributorLicenseAgreement success success success
CodeOfConduct success success success

The action successfully authenticated to splunk/cla-agreement using the in-job-minted installation token — i.e. the failure observed on PR #971 (Could not retrieve repository contents. Status: unknown) is fixed.

Note about the test

The end-to-end run required momentarily widening the if: guard on the action step to also accept github.event_name == 'pull_request', so the test could trigger from the head branch (under pull_request_target, the workflow file would have been read from main, defeating the purpose of testing a branch change). That commit has been reverted (git reset --hard HEAD~1 + force push). What remains on the branch is:

  1. fix(agreements): mint GitHub App installation token in-job
  2. fix(agreements): bridge secrets to step if via job env

A prior intermediate run with the production if: guards also proved the App-token mint step worked: https://github.com/splunk/splunk-add-on-for-crowdstrike-fdr/actions/runs/27171437154

@mbruzda-splunk mbruzda-splunk merged commit 24ba118 into main Jun 9, 2026
12 checks passed
@mbruzda-splunk mbruzda-splunk deleted the fix/agreements-mint-app-token-in-job branch June 9, 2026 08:29
@srv-rr-github-token

Copy link
Copy Markdown

🎉 This PR is included in version 1.7.2 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants