Pipeline Identities, Part 1: Your Repository and GITHUB_TOKEN

In this part of the pipelines identities you'll create the application repository you'll be using throughout the lab.
Here are the calls you'll cover:

  • call 1, you โ†’ your repository: you push, over SSH or HTTPS;
  • call 2, job โ†’ GitHub: the job checks out the code with GITHUB_TOKEN.

It needs only a GitHub account.

Create the repository

On GitHub, create a New repository:

  • Name: pipeline-identities.
  • Visibility: Private.
    • Then even reading the code needs a credential, and the job's checkout shows GITHUB_TOKEN at work.
    • Actions on a private repository use your account's free minutes; this lab needs a few.
  • Leave the repository empty: no README, no .gitignore.

Set up push access

Choose one of the two credentials, and follow its steps only. The remote's URL decides which one git sends.

Option 1: an SSH key

The key reaches every repository your account may write to.

  1. Create a key pair, if you have none in ~/.ssh/:

    1$ ssh-keygen -t ed25519 -C "<your-email>"
    
  2. On GitHub, open Settings โ†’ SSH and GPG keys โ†’ New SSH key, and paste the public key, the contents of ~/.ssh/id_ed25519.pub.

  3. Check that GitHub accepts the key:

    1$ ssh -T git@github.com
    2Hi <you>! You've successfully authenticated, but GitHub does not provide shell access.
    
  4. Clone the repository over SSH:

    1$ git clone git@github.com:<you>/pipeline-identities.git
    2Cloning into 'pipeline-identities'...
    3warning: You appear to have cloned an empty repository.
    4$ cd pipeline-identities
    
Option 2: a personal access token

A fine-grained token can be limited to this one repository.

  1. On GitHub, open Settings โ†’ Developer settings โ†’ Personal access tokens โ†’ Fine-grained tokens โ†’ Generate new token.

  2. Fill it in:

    • Token name: pipeline-identities push;
    • Expiration: 30 days;
    • Repository access: Only select repositories, and pick pipeline-identities;
    • Permissions โ†’ Repository permissions:
      • Contents: Read and write, to push;
      • Workflows: Read and write, since GitHub refuses a push that changes .github/workflows/ without it.
  3. Generate token, and copy it: GitHub shows it once.

  4. Tell git to remember the token for an hour, so you type it once:

    1$ git config --global credential.helper 'cache --timeout=3600'
    
  5. Clone the repository over HTTPS, typing your GitHub user name and the token as the password:

    1$ git clone https://github.com/<you>/pipeline-identities.git
    2Cloning into 'pipeline-identities'...
    3Username for 'https://github.com': <you>
    4Password for 'https://<you>@github.com':
    5warning: You appear to have cloned an empty repository.
    6$ cd pipeline-identities
    

Add the first workflow

Create .github/workflows/pipeline.yml:

 1name: pipeline
 2
 3on:
 4  push:
 5    branches: [main]
 6  workflow_dispatch:
 7
 8# What GITHUB_TOKEN may do in this workflow. Everything not listed is "none".
 9permissions:
10  contents: read
11
12jobs:
13  deliver:
14    runs-on: ubuntu-latest
15    steps:
16      - name: Check out the code with GITHUB_TOKEN
17        uses: actions/checkout@v7
18
19      - name: Read the repository with GITHUB_TOKEN
20        env:
21          GH_TOKEN: ${{ github.token }}
22        run: gh api "repos/$GITHUB_REPOSITORY" --jq '{full_name, private, default_branch}'
23
24      - name: Try to open an issue with GITHUB_TOKEN
25        env:
26          GH_TOKEN: ${{ github.token }}
27        run: gh issue create --title "Opened by the pipeline" --body "Run $GITHUB_RUN_ID"
  • permissions: says what GITHUB_TOKEN may do: read the code, and nothing else.
  • actions/checkout clones the repository with GITHUB_TOKEN, which it uses unless told otherwise.
  • gh api reads the repository's settings with the same token.
  • gh issue create asks for something the permissions leave out: opening an issue.

Push, and read the first run

  1. Commit, and push to main. The push is call 1, and it starts the workflow.

    1$ git add .
    2$ git commit -m "First workflow"
    3$ git branch -M main
    4$ git push -u origin main
    
  2. Open Actions โ†’ pipeline, then the run and its job, deliver.

  3. Read its steps:

    • Check out the code: the clone succeeds, on a private repository, with no credential of yours.

    • Read the repository prints its settings:

      1{"full_name":"<you>/pipeline-identities","private":true,"default_branch":"main"}
      
    • Try to open an issue fails, and the job fails with it:

      1GraphQL: Resource not accessible by integration (createIssue)
      
      • "Integration" is GitHub's word for an app: the token belongs to the GitHub Actions app, not to you.
      • The app holds only contents: read here, so GitHub refuses.

Grant the token one more right

  1. Add one line to permissions::

    1permissions:
    2  contents: read
    3  issues: write
    
  2. Commit and push.

  3. Check the run: it passes, and under Issues the new issue is opened by github-actions, the bot, not by you.

What the run shows about GITHUB_TOKEN:

  • Every job gets a token of its own, made when the job starts.
  • It expires when the job ends.
  • It reaches this repository only, with the rights permissions: lists.

Remove the test steps

The issue was only a test. Remove issues: write and the two gh steps, then commit and push: the pipeline keeps the checkout alone.